一直没有在项目里用过NHibernate3.2的CodeFirst 这次因为项目需要用到Oracle数据库而我对EF对Oracle支持心里犯嘀咕所以为保险起见我用NHibernate,以前都是写就映射文件的,现在3.2里已经集成了Maping Bycode工具可以说是NHibernate对CodeFirst支持得很不错了!我也不想采用Xml文件了(至于原因大家都懂得的!)
明白了大多数的NHibernate映射参数采用CodeFist也应该不是什么难事!
所以今天就试了一把,以前也试过但只粗略的试了一下!出现了以下问题,(结果谷爹 度娘 一起用也没查到个所以然!只是找了一堆EFCodeFirst的东西,NHibernate的几乎很少)小弟真不知道是怎么回事儿,所以特向园子里的大侠请教!
废话不多说了,先上代码:
public class Student
{
public virtual int StudentID { set; get; }
public virtual string StudentName { set; get; }
public virtual IList<CurrClass> CurrClasses { set; get; }
}
public class CurrClass
{
public virtual int ClassID { set; get; }
public virtual int ClassName { set; get; }
public virtual IList<Student> Students { set; get; }
}
public class CurrClassMap : ClassMapping<CurrClass>
{
public CurrClassMap()
{
this.Id(p => p.ClassID, map => {
map.Generator(Generators.Native);
});
this.Property(p => p.ClassName);
this.Bag(p => p.Students, map => {
map.Table("Student_Class");
});
}
}
public class StudentMap : ClassMapping<Student>
{
public StudentMap()
{
this.Id(p => p.StudentID, map =>
{
map.Generator(Generators.Native);
});
this.Property(p => p.StudentName, map =>
{
map.Length(500);
});
this.Bag(p => p.CurrClasses, map => {
map.Table("Student_Class");
});
}
}
用过的朋友一看就知道是个多对多的关系!看似没什么问题,那么我们来看下生成映射文件是不是够标准:
<?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="DALTestCase.domain" assembly="DALTestCase" xmlns="urn:nhibernate-mapping-2.2"> <class name="CurrClass"> <id name="ClassID" type="Int32"> <generator class="native" /> </id> <property name="ClassName" /> <bag name="Students" table="Student_Class"> <key column="currclass_key" /> <many-to-many class="Student" /> </bag> </class> <class name="Student"> <id name="StudentID" type="Int32"> <generator class="native" /> </id> <property name="StudentName" length="500" /> <bag name="CurrClasses" table="Student_Class"> <key column="student_key" /> <many-to-many class="CurrClass" /> </bag> </class> </hibernate-mapping>
很不错!和手写的没两样!
再来看看我们生成的数据库脚本(我这里是用的Sql2005):
if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKCF48CF07D9A53447]') AND parent_object_id = OBJECT_ID('Student_Class')) alter table Student_Class drop constraint FKCF48CF07D9A53447 if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKCF48CF07401A93]') AND parent_object_id = OBJECT_ID('Student_Class')) alter table Student_Class drop constraint FKCF48CF07401A93 if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKCF48CF077158C5E0]') AND parent_object_id = OBJECT_ID('Student_Class')) alter table Student_Class drop constraint FKCF48CF077158C5E0 if exists (select * from dbo.sysobjects where id = object_id(N'CurrClass') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table CurrClass if exists (select * from dbo.sysobjects where id = object_id(N'Student_Class') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Student_Class if exists (select * from dbo.sysobjects where id = object_id(N'Student') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Student create table CurrClass ( ClassID INT IDENTITY NOT NULL, ClassName INT null, primary key (ClassID) ) create table Student_Class ( currclass_key INT not null, elt INT not null,///这里就是我说的莫名奇妙的多出来了一个字段 student_key INT not null ) create table Student ( StudentID INT IDENTITY NOT NULL, StudentName NVARCHAR(500) null, primary key (StudentID) ) alter table Student_Class add constraint FKCF48CF07D9A53447 foreign key (elt) references Student alter table Student_Class add constraint FKCF48CF07401A93 foreign key (currclass_key) references CurrClass alter table Student_Class add constraint FKCF48CF077158C5E0 foreign key (student_key) references Student
正在我看的时侯突然发现,第三个表里竟然多了一个elt的字段,到底是怎么回事儿呢!?现在我也没闹明白!怎么会凭空多个字段出来!?
结果表结构就变成了下面的这个样子:

至于生成的涉及Student_Class的这个表生成的SQL语句都会存在这个elt的字段。如果操作Student_Class表生成的SQL语句会出现不能执行的错误!
为什么会出现elt的字段?为什么用Xml就不会出现elt的字段?这个elt有什么用处!?
希望大侠们可以帮我解惑!!!

public class Product
{
public int PID
{
get;
set;
}
public string PName
{
get;
set;
}
public virtual IList<Order> Orders
{
get;
set;
}
}
public class Order
{
public int OrderID
{
get;
set;
}
public string OrderName
{
get;
set;
}
public virtual IList<Product> Products
{
get;
set;
}
}
映射配置:
public class ProductConfig:EntityTypeConfiguration<Product>
{
public ProductConfig()
{
this.HasKey(p => p.PID);
this.Property(p => p.PName).HasMaxLength(255);
this.HasMany(p => p.Orders)
.WithMany(p => p.Products)
.Map(map => {
map.MapLeftKey("ProductID");
map.MapRightKey("OrderID");
map.ToTable("Product_Order");
});
}
}
public class OrderConfig : EntityTypeConfiguration<Order>
{
public OrderConfig()
{
this.HasKey(p => p.OrderID);
this.Property(p => p.OrderName).HasMaxLength(255);
}
}
NH实体配置:
<class name="Product" table="T_Product">
<id name="PID" column="[PID]">
<generator class="native"/>
</id>
<property name="PName" column="PName" type="string" length="255"/>
<bag name="Orders" table="Product_Order">
<key column="ProductID"/>
<many-to-many class="Order" column="OrderID"/>
</bag>
</class>
<class name="Order" table="T_Order">
<id name="OrderID" column="[OrderID]">
<generator class="native"/>
</id>
<property name="OrderName" column="OrderName" type="string" length="255"/>
<bag name="Products" table="Product_Order">
<key column="OrderID"/>
<many-to-many class="Product" column="ProductID"/>
</bag>
</class>
EF的Many to Many 关系清晰明了!实在没有什么好说的!
上篇比较NH和EF一对一的关系写得有点仓促。由于是第一次写Blog,写得不好请大家多多见谅。
在这里只对NH和EF OR 映射部分做个简单的对比,由于本人对EF还不太熟悉在这里不做深层讨论。
EF OR关系对本人来说理解的有点费劲,有时不知道是什么意思。(可能是我悟性太低吧!)
感谢大家的捧场!
一对多的关系我们拿学生和班级来做个例子。
下边是学生和班级的数据库结构图.:

班级和学生的对像模型图:

EF:学生和班级实体
public class Student
{
public int? StuID { get; set; }
public string StudentName { get; set; }
public virtual Class Class { set; get; }
public int? ClassID { get; set; }
}
public class Class
{
public int? ClassID { get; set; }
public string ClassName { get; set; }
public virtual IList<Student> Students { get; set; }
}
NH:学生和班级实体
public class Student
{
public virtual int? StuID { get; set; }
public virtual string StudentName { get; set; }
}
从对像模型上来看我更倾向NH,像EF上边的这样写感觉有点别扭!(主要还是在外键字段上)
public class Class
{
public virtual int? ClassID { get; set; }
public virtual string ClassName { get; set; }
public virtual IList<Student> Students { get; set; }
}
EF中学生和班级表实体关系定义:
public class StudentConfig : EntityTypeConfiguration<Student>
{
public StudentConfig()
{
this.HasKey(p => p.StuID).Property(p=>p.StuID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(p => p.StudentName).HasMaxLength(255).HasColumnName("StudentName");
this.HasMany(p => p.Students).WithRequired(p => p.Class).HasForeignKey(p => p.ClassID);
this.ToTable("T_Student");
}
}
public class CLassConfig : EntityTypeConfiguration<Class>
{
public CLassConfig()
{
this.HasKey(p => p.ClassID).Property(p => p.ClassID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(p => p.ClassName).HasColumnName("ClassName").HasMaxLength(255);
this.ToTable("T_Class");
}
}
NH中学生和班级表实体关系定义:
<class name="Student" table="N_Student" lazy="true" >
<id name=" StuID " type="int" column=" StuID ">
<generator class="native"/>
</id>
<property name=" StudentName " type="string">
<column name=" StudentName " length="50"/>
</property>
</class>
<class name="Class" table="N_Class" lazy="true" >
<id name=" ClassID " type="int" column="ClassID">
<generator class="native"/>
</id>
<property name=" ClassName " type="string">
<column name=" ClassName " length="50"/>
</property>
<bag name="Students">
<key column=" ClassID"/>
<one-to-many class="Student"/>
</bag>
</class>
一直以来我都为寻找一个合适的Orm,以前用过NBear感觉不错,后来转到Nhibeante特别是Nhibeante的模型映射感觉很强大,也很顺手。随着做了几个项目之后,发现现在的好多项目是以数据库为中心的,往往和数据库设计的标准大相径庭,这就让我想起了当前有一面之缘的EF,听说EF升级到4.2网评反响不错!一直以来都没有升级到.net 4.0也许太我Out了吧!呵。。
元旦放假闲在家里没有事儿,所以看看EF。Orm既然是关系映射模型,那学Orm的时侯先学的就是关系映射。所有Orm关系无非就是:一对一,多对一(一对多),多对多。那我们就来对比一下Nh和EF是如何处理数据关系的。
一、 一对一关系映射
一对一的关系映射最好的例子就是一个人都有一个身份证.下面我们就用这个例子。
EF实体:
UserInfo.cs
public class UserInfo
{
public int userid
{
get;
set;
}
public string username
{
get;
set;
}
public int Carid
{
get;
set;
}
public virtual CardInfo CardInfo
{
get;
set;
}
}
CardInfo.cs
public class CardInfo
{
public int Carid
{
get;
set;
}
public string CardName
{
get;
set;
}
}
NH实体:
UserInfo.cs
public class UserInfo
{
Public virtual int userid
{
get;
set;
}
Public virtual string username
{
get;
set;
}
public virtual CardInfo CardInfo
{
get;
set;
}
}
CardInfo.cs
public class CardInfo
{
Public virtual int Carid
{
get;
set;
}
Public virtual string CardName
{
get;
set;
}
}
猛的一看这样的模型没错,不知道EF为什么不像NH一样不能自动创建外键(Carid)这样看起来不怎么符合领域模型。就因为这个让我习惯了好一会儿!比较之我更习惯NH映射的模型.这样子一看就知道一个人手里拿了一个身份证.
关系映射:
EF UserInfo映射类:
public class UserInfoConfig : EntityTypeConfiguration<UserInfo>
{
public UserInfoConfig()
{
this.HasKey(p => p.userid);//定义主键
this.Property(p => p.username).HasMaxLength(255);//普通属性映射
this.HasRequired(p => p.CardInfo).WithMany().HasForeignKey(p => p.Carid);//一对一的映射
this.ToTable("T_UserInfo");//生成表
}
}
EF CardInfo映射类:
public class CardInfoConfig : EntityTypeConfiguration<CardInfo>
{
public CardInfoConfig()
{
this.HasKey(p => p.Carid);
this.Property(p => p.CardName).HasMaxLength(255);
this.ToTable("T_CardInfo");
}
}
这样的映射是不是感觉很爽?我也是这么认为,可我还是不大习惯。可能是Nh 用XML映射用多了吧!让我们看下Nh One to One的映射.
<class name="UserInfo" table="N_UerInfo">
<id name="userid" column="[userid]">
<generator class="native"/>
</id>
<property name="username" type="string" column="[username]" length="255"/>
<one-to-one name="CardInfo" constrained="true"/>
</class>
<class name="CardInfo" table="N_CardInfo">
<id name="Carid" column="[Carid]">
<generator class="native"/>
</id>
<property name="CardName" column="[CardName]" type="string" length="255"/>
</class>
NH这样子映射虽然很麻烦但一看就能明白.很喜欢这样的。有很多人不喜欢XML映射说很麻烦,其实XML的可读性应该比程序好多了!至少我是这么认为的。一但多起来那就不那么好办了!
今天就到这了吧!下次再对比其他的几种关系。

