尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

将一个实体映射到多个表

将一个实体映射到多个表
📅 发布时间:2026/7/3 1:17:10

在数据库设计中这常被称作垂直分割。还是通过例子来看具体实现。我们给产品类增加2个新属性:

1

2

3

4

5

6

7

8

9

publicclassProduct

{

publicintId {get;set; }

publicstringName {get;set; }

publicstringDescription {get;set; }

//new property

publicfloatPrice {get;set; }

publicfloatWeight {get;set; }

}

我们希望将新属性存储在另一张数据表中,可以按如下方式配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

publicclassProductMap : EntityTypeConfiguration<Product>

{

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);

}

}

代码一目了然,分开指定属性和相应的表即可。生成的迁移代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

CreateTable(

"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增加的属性独立出来:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

publicclassProduct

{

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个实体类,接下来的配置将把它们映射到一张表:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

publicclassProductDetailMap : EntityTypeConfiguration<ProductDetail>

{

publicProductDetailMap()

{

HasKey(pd=>pd.Id).HasRequired(pd => pd.Product).WithRequiredPrincipal(p=>p.ProductDetail);

ToTable("Product");

}

}

publicclassProductMap : EntityTypeConfiguration<Product>

{

publicProductMap()

{

HasKey(p => p.Id);

ToTable("Product");

}

}

生成的迁移代码可以看出,两个实体将被保存到一张表:

1

2

3

4

5

6

7

8

9

10

11

CreateTable(

"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的HasKey<TKey>方法指定主键)。这样实体才能被EF Context这个缓存容器进行维护,并与数据库中相应的条目实现一一对应来支持增删改查。

变更跟踪是默认启用的,可以通过配置DbContext来关闭这个功能,如下代码:

1

context.Configuration.AutoDetectChangesEnabled =false;

注意:

一般来说不建议关闭变更跟踪,除非是只读(只读情况下用AsNoTracking获取实体并自己做缓存应该更好)。

在关闭变更跟踪的情况下,可以通过如下方法手动调用一次变更检测(或者用下文将介绍的手动状态改变),这样后续的SavaChanges操作才能正确完成。

1

context.ChangeTracker.DetectChanges();

另外要注意的一点是,变更跟踪只能在一个上下文内有效。即如果有两个DbContext的实例,两个DbContext各自作用域内的变更跟踪是独立的。

除了使用自动变更跟踪,在对性能要求极端的情况下,也可以手动控制实体的状态(另一种情况是实体本不在当前Context中,要加入当前Context控制下必须手动完成)。

与实体变更控制最密切的就是DBEntityEntry类,这个类的对象正是通过前文介绍的DbContext的Entry<T>方法获得的。DBEntityEntry最重要的属性就是获取实体状态的State属性。

1

2

3

varentry = dbCtx.Entry(student);

Console.WriteLine("Entity State: {0}", entry.State );

context.Entry(student).State = EntityState.Deleted;

上面几行代码展示了查询与修改EF Context中实体状态的方法。

最后这段综合的代码示例演示了在关闭变更跟踪的情况下,手动修改实体状态实现更新。

1

2

3

4

5

6

context.Configuration.AutoDetectChangesEnabled =false;

varstudent = context.Set<Student>().FirstOrDefault(s => s.StudentName =="张三");

student.StudentName ="王五";

varstuEntry = context.Entry(student);

stuEntry.State = EntityState.Modified;

context.SaveChanges();

AsNoTracking

对于只读操作,强烈建议使用AsNoTracking进行数据获取,这样省去了访问EF Context的时间,会大大降低数据获取的时间。

1

varstudent = context.Set<Student>().AsNoTracking().FirstOrDefault(s => s.StudentName =="王五");

由于没有受EF Context管理,对于这样获取到的数据,更新的话需要先Attach然后手动修改状态并SaveChanges。

1

2

3

4

5

student.StudentName ="张三";

context.Set<Student>().Attach(student);

varstuEntry = context.Entry(student);

stuEntry.State = EntityState.Modified;

context.SaveChanges();

相关新闻

  • 神经外科手术模拟器的实时形变建模与深度学习应用
  • PDF 提取表格到 Excel(含扫描版),断网批量可用
  • 从零到赏金猎人:网络安全速成与漏洞挖掘完整实战方案

最新新闻

  • Spring Boot实现百万级数据统计与Excel导出优化
  • 机器学习驱动的应用性能预测实战指南
  • 图像分类入门:CNN原理与Python实战指南
  • web安全代码基础-PHP(代码/命令执行安全)
  • 《开心消消乐》为什么能成为国民级三消游戏
  • KWM转MP3:从酷我加密容器到通用格式,5种技术方案完全解析

日新闻

  • JMeter接口测试实战:从核心元件到复杂场景构建
  • Java Applet版刽子手游戏源码:含完整项目结构、吊杆绘图与胜负逻辑
  • 使用Apache JMeter对RoadRunner PHP应用进行性能测试与调优指南

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号