配置实体映射
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity().HasKey(t => t.Id);
base.OnModelCreating(modelBuilder);
}
使用上面这种方式的一个问题是OnModelCreating方法会随着映射配置的增多越来越大。一种更好的方式是继承EntityTypeConfiguration并在这个类中添加映射代码如:
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
this.ToTable("Product");
this.HasKey(p => p.Id);
this.Property(p => p.Name).IsRequired();
}
}
通过反射自动映射
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof
(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
映射API
ToTable:指定映射到的数据库表的名
HasKey:配置主键(也用于配置关联主键)
Property: 配置字段
Ignore 指定忽略哪个属性
使用modelBuilder.HasDefaultSchema(“newdbo”);可以给所有映射实体指定schema。
PrimitivePropertyConfiguration还有许多可配置的选项,如HasColumnOrder指定列在表中次序,IsOptional指定列是否可空,HasPrecision
指定浮点数的精度等等,不再列举。
ToTable(“Product”);
ToTable(“Product”,”newdbo”);//指定schema,不使用默认的dbo
HasKey(p => p.Id);//普通主键
HasKey(p => new {p.Id, p.Name});//关联主键
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);//不让主键作为Identity自动生成
Property(p => p.Name).IsRequired().HasMaxLength(20).HasColumnName(“ProductName”).IsUnicode(false);//非空,最大长度20,自定义
列名,列类型为varchar而非nvarchar
Ignore(p => p.Description);
1对1关联
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
//第一组(两条效果完全相同)
HasRequired(p => p.WarrantyCard).WithRequiredDependent(i => i.Product);
HasRequired(p => p.WarrantyCard).WithOptional(i => i.Product);
//第二组(两条效果完全相同)
HasRequired(p => p.WarrantyCard).WithRequiredPrincipal(i => i.Product);
HasOptional(p => p.WarrantyCard).WithRequired(i => i.Product);
}
}
public class WarrantyCardMap : EntityTypeConfiguration
{
public WarrantyCardMap()
{
ToTable("WarrantyCard");
HasKey(i => i.ProductId);
}
}
单向1对多关联(可为空)
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
HasOptional(p => p.Invoice).WithMany().HasForeignKey(p => p.InvoiceId);
}
}
public class InvoiceMap : EntityTypeConfiguration
{
public InvoiceMap()
{
ToTable("Invoice");
HasKey(i => i.Id);
}
}
HasOptional表示一个产品可能会有发票,WithMany的参数为空表示我们不需要由发票关联到产品,HasForeignKey用来指定Product表中的外键
列。
还可以通过WillCascadeOnDelete()配置是否级联删除
运行迁移后,数据库生成的Product表外键可为空(注意实体类中表示外键的属性一定要为Nullable类型,不然迁移代码不能生成)。
下面写段代码来测试下这个映射配置,先是创建一个测试对象
单向1对多关联(不可为空)
HasRequired(p => p.Certification).WithMany().HasForeignKey(p=>p.CertificationId);
双向1对多关联
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
HasMany(p => p.Photos).WithRequired(pp => pp.Product).HasForeignKey(pp => pp.ProductId);
}
}
public class ProductPhotoMap : EntityTypeConfiguration
{
public ProductPhotoMap()
{
ToTable("ProductPhoto");
HasKey(pp => pp.Id);
}
}
第二种方法
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
}
}
public class ProductPhotoMap : EntityTypeConfiguration
{
public ProductPhotoMap()
{
ToTable("ProductPhoto");
HasKey(pp => pp.Id);
HasRequired(pp => pp.Product).WithMany(p => p.Photos).HasForeignKey(pp => pp.ProductId);
}
}
多对多关联
public class ProductMap : EntityTypeConfiguration
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
HasMany(p => p.Tags).WithMany(t => t.Products).Map(m => m.ToTable("Product_Tag_Mapping"));
}
}
public class TagMap : EntityTypeConfiguration
{
public TagMap()
{
ToTable("Tag");
HasKey(t => t.Id);
}
}
补充
示例中用到多次HasForeignKey()方法来指定外键,如果实体类中不存在表示外键的属性,我们可以用下面的方式指定外键列,这样这个外键列
只存在于数据库,不存在于实体中:
HasOptional(p => p.Invoice).WithMany().Map(m => m.MapKey("DbOnlyInvoiceId"));
如果多对多关系表中有其它列请配置两个一对多双向关联。