当前位置: 首页 > news >正文

将一个实体映射到多个表

在数据库设计中这常被称作垂直分割。还是通过例子来看具体实现。我们给产品类增加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();

http://www.jsqmd.com/news/1112257/

相关文章:

  • CoffeeDeveloper
  • Azure Local 离线操作总览(系列篇之一)
  • KMR221与PIC18F47K40构建高精度低功耗电压管理系统
  • Multimodal-CoT:多模态思维链的工程落地与工业实践
  • 混合量子经典Benders算法在MILP优化中的应用
  • 从零到赏金猎人:网络安全速成与漏洞挖掘完整实战方案
  • PDF 提取表格到 Excel(含扫描版),断网批量可用
  • 做一只稳健的“老龟”:从底层测试到新负责人的碎碎念
  • LV30条码扫描器与PIC18F87J60微控制器集成方案
  • 小学1-6年级暑假作业:语文+数学+英语(可打印电子版)
  • 数据结构——栈与队列:原理、实现与经典应用
  • Python 零基础入门:运算符、格式化输出与字符编码全解(避坑版)
  • 5大核心策略构建企业级CMDB:open-cmdb实战部署与优化完整指南
  • 7个节点串成Agent管道,6个场景全过,但和线上的差距都在细节里
  • Altium Designer差分对设计全攻略:从原理到高速PCB实战
  • 精通XUnity.AutoTranslator:突破Unity游戏语言壁垒的终极解决方案
  • 美国最高法院限制警方获取个人位置历史记录的权限!守护数字隐私的重大胜利:最高法院为警方调取个人位置信息戴上“紧箍咒”
  • 5分钟掌握全平台资源下载:从微信视频号到抖音快手的一站式解决方案
  • 【2025实测指南】录音转行动项用什么工具?新手避坑干货
  • “探照灯是怎么扫出那堵墙的?“:连续碰撞检测的底层计算揭秘
  • FIRRTL宽度推断:形式化建模与高效求解算法
  • ComfyUI-WanVideoWrapper Block Swap技术深度解析:实现40% VRAM优化突破
  • DIN DIEN DSIN 简述
  • 全网最简 Gorm 教程 | Gorm 模型定义
  • 2026年主流企业网盘深度测评+选型推荐|初创/中大型/涉密企业全覆盖
  • 基于IIM-42652 IMU的6DoF运动追踪系统设计与实现
  • 美国悬赏1000万美元,征集有关俄罗斯黑客攻击Signal账户的信息
  • 5.7万 Star!GitHub 爆火的 AI 求职神器
  • crictl 实战指南:没有 docker 命令后,Kubernetes 节点该怎么排障?
  • AI技术现状与未来:从大模型能力边界到开发者转型