配置实体映射

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasKey(t => t.Id);

base.OnModelCreating(modelBuilder);
}

使用上面这种方式的一个问题是OnModelCreating方法会随着映射配置的增多越来越大。一种更好的方式是继承EntityTypeConfiguration并在这个类中添加映射代码如:

public class ProductMap : EntityTypeConfiguration<Product>
{
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<Product>
{
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<WarrantyCard>
{
public WarrantyCardMap()
{
ToTable("WarrantyCard");
HasKey(i => i.ProductId);
}
}

单向1对多关联(可为空)

public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
HasOptional(p => p.Invoice).WithMany().HasForeignKey(p => p.InvoiceId);
}
}

public class InvoiceMap : EntityTypeConfiguration<Invoice>
{
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<Product>
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
HasMany(p => p.Photos).WithRequired(pp => pp.Product).HasForeignKey(pp => pp.ProductId);
}
}

public class ProductPhotoMap : EntityTypeConfiguration<ProductPhoto>
{
public ProductPhotoMap()
{
ToTable("ProductPhoto");
HasKey(pp => pp.Id);
}
}

第二种方法

public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
ToTable("Product");
HasKey(p => p.Id);
}
}

public class ProductPhotoMap : EntityTypeConfiguration<ProductPhoto>
{
public ProductPhotoMap()
{
ToTable("ProductPhoto");
HasKey(pp => pp.Id);
HasRequired(pp => pp.Product).WithMany(p => p.Photos).HasForeignKey(pp => pp.ProductId);
}
}

多对多关联

public class ProductMap : EntityTypeConfiguration<Product>
{
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<Tag>
{
public TagMap()
{
ToTable("Tag");
HasKey(t => t.Id);
}
}

补充

示例中用到多次HasForeignKey()方法来指定外键,如果实体类中不存在表示外键的属性,我们可以用下面的方式指定外键列,这样这个外键列

只存在于数据库,不存在于实体中:

HasOptional(p => p.Invoice).WithMany().Map(m => m.MapKey("DbOnlyInvoiceId"));

如果多对多关系表中有其它列请配置两个一对多双向关联。