将一个实体映射到多个表 在数据库设计中这常被称作垂直分割。还是通过例子来看具体实现。我们给产品类增加2个新属性123456789publicclassProduct{publicintId {get;set; }publicstringName {get;set; }publicstringDescription {get;set; }//new propertypublicfloatPrice {get;set; }publicfloatWeight {get;set; }}我们希望将新属性存储在另一张数据表中可以按如下方式配置1234567891011121314151617publicclassProductMap : EntityTypeConfigurationProduct{publicProductMap(){Map(m {m.Properties(t new{ t.Id, t.Name, t.Description });m.ToTable(Product);}).Map(m {m.Properties(t new{ t.Id, t.Price, t.Weight });m.ToTable(ProductDetail);});HasKey(p p.Id);}}代码一目了然分开指定属性和相应的表即可。生成的迁移代码如下123456789101112131415161718192021CreateTable(sample.Product,c new{Id c.Int(nullable:false, identity:true),Name c.String(),Description c.String(maxLength: 200),}).PrimaryKey(t t.Id);CreateTable(sample.ProductDetail,c new{Id c.Int(nullable:false),Price c.Single(nullable:false),Weight c.Single(nullable:false),}).PrimaryKey(t t.Id).ForeignKey(sample.Product, t t.Id).Index(t t.Id);是不是很眼熟对和之前配置1 - 1映射生成的迁移代码一模一样。当然生成的查询语句也是一样的。将两个实体映射到一张表我们把上一个例子中给Product增加的属性独立出来123456789101112131415publicclassProduct{publicintId {get;set; }publicstringName {get;set; }publicstringDescription {get;set; }publicvirtualProductDetail ProductDetail {get;set; }}publicclassProductDetail{publicintId {get;set; }publicfloatPrice {get;set; }publicfloatWeight {get;set; }publicvirtualProduct Product {get;set; }}现在我们有2个实体类接下来的配置将把它们映射到一张表1234567891011121314151617publicclassProductDetailMap : EntityTypeConfigurationProductDetail{publicProductDetailMap(){HasKey(pdpd.Id).HasRequired(pd pd.Product).WithRequiredPrincipal(pp.ProductDetail);ToTable(Product);}}publicclassProductMap : EntityTypeConfigurationProduct{publicProductMap(){HasKey(p p.Id);ToTable(Product);}}生成的迁移代码可以看出两个实体将被保存到一张表1234567891011CreateTable(dbo.Product,c new{Id c.Int(nullable:false, identity:true),Name c.String(),Description c.String(maxLength: 200),Price c.Single(nullable:false),Weight c.Single(nullable:false),}).PrimaryKey(t t.Id);映射部分就到这里了。休息下吧。中场休息借中场休息时间鄙视一下那些转载不保留原链接的网站尤其像numCTO这种。变更跟踪变更跟踪指的是对缓存于EF Context中的实体的状态的跟踪与改变。所以了解变更跟踪先看了解一下实体在EF Context中的几种状态。下面是国外某网站看到的一幅很不错的图直接拿过来用了。图3. EF Context中实体状态 来源支持变更跟踪最关键的一点是实体必须有主键(如前文介绍通过Fluent API的HasKeyTKey方法指定主键)。这样实体才能被EF Context这个缓存容器进行维护并与数据库中相应的条目实现一一对应来支持增删改查。变更跟踪是默认启用的可以通过配置DbContext来关闭这个功能如下代码1context.Configuration.AutoDetectChangesEnabled false;注意一般来说不建议关闭变更跟踪除非是只读只读情况下用AsNoTracking获取实体并自己做缓存应该更好。在关闭变更跟踪的情况下可以通过如下方法手动调用一次变更检测(或者用下文将介绍的手动状态改变)这样后续的SavaChanges操作才能正确完成。1context.ChangeTracker.DetectChanges();另外要注意的一点是变更跟踪只能在一个上下文内有效。即如果有两个DbContext的实例两个DbContext各自作用域内的变更跟踪是独立的。除了使用自动变更跟踪在对性能要求极端的情况下也可以手动控制实体的状态另一种情况是实体本不在当前Context中要加入当前Context控制下必须手动完成。与实体变更控制最密切的就是DBEntityEntry类这个类的对象正是通过前文介绍的DbContext的EntryT方法获得的。DBEntityEntry最重要的属性就是获取实体状态的State属性。123varentry dbCtx.Entry(student);Console.WriteLine(Entity State: {0}, entry.State );context.Entry(student).State EntityState.Deleted;上面几行代码展示了查询与修改EF Context中实体状态的方法。最后这段综合的代码示例演示了在关闭变更跟踪的情况下手动修改实体状态实现更新。123456context.Configuration.AutoDetectChangesEnabled false;varstudent context.SetStudent().FirstOrDefault(s s.StudentName 张三);student.StudentName 王五;varstuEntry context.Entry(student);stuEntry.State EntityState.Modified;context.SaveChanges();AsNoTracking对于只读操作强烈建议使用AsNoTracking进行数据获取这样省去了访问EF Context的时间会大大降低数据获取的时间。1varstudent context.SetStudent().AsNoTracking().FirstOrDefault(s s.StudentName 王五);由于没有受EF Context管理对于这样获取到的数据更新的话需要先Attach然后手动修改状态并SaveChanges。12345student.StudentName 张三;context.SetStudent().Attach(student);varstuEntry context.Entry(student);stuEntry.State EntityState.Modified;context.SaveChanges();