《EntityFramework6Recipes》中文翻译系列(30)第六章继承与建模高级应用之多对多关联chinafucan

现在,你应该对实体框架中基本的建模有了一定的了解,本章将帮助你解决许多常见的、复杂的建模问题,并解决你可能在现实中遇到的建模问题。

本章以多对多关系开始,这个类型的关系,无论是在现存系统还是新项目的建模中都非常普遍。接下来,我们会了解自引用关系,并探索获取嵌套对象图的各种策略。最后,本章以继承的高级建模和实体条件结束。

问题

你想获取链接表的键,链接表链接两个多对多关联的实体。

解决方案

假设你一个包含Event和Organizer实体和它们之前多对多关联的模型,如图6-1所示。

图6-1Event和Organizer实体和它们之前多对多关联的模型

正如我们在第二章演示的,多对多关联代表的是数据库中的一个中间表,这个中间表叫做链接表(译注:也称关联表,但使用这个词会容易与关系两边的表的描述(关联表)产生混淆,所以这里使用链接表一词)。链接表包含关系两边的外键(如图6-2)。当链接表中没有额外的列时,实体框架在导入关联表时,向导会在两个关联表间生成一个多对多的关联。链接表不被表示为一个实体,而是被表示成一个对多对多的关联。

图6-2数据库关联图,展示链接表EventOrganizer包含两个关联表Event和Oranizer的外键

为了获取实体键EventId,和OrganizerId,我们可以使用嵌套的from从句,或者SelectMany()方法。如代码清单6-1所示。

代码清单6-1.使用嵌套from从句和SelectMany()方法获取链接表

1using(varcontext=newRecipe1Context())2{3varorg=newOrganizer{Name="CommunityCharity"};4varevt=newEvent{Name="Fundraiser"};5org.Events.Add(evt);6context.Organizers.Add(org);7org=newOrganizer{Name="BoyScouts"};8evt=newEvent{Name="EagleScoutDinner"};9org.Events.Add(evt);10context.Organizers.Add(org);11context.SaveChanges();12}1314using(varcontext=newRecipe1Context())15{16varevsorg1=fromevincontext.Events17fromorganizerinev.Organizers18selectnew{ev.EventId,organizer.OrganizerId};19Console.WriteLine("Usingnestedfromclauses...");20foreach(varpairinevsorg1)21{22Console.WriteLine("EventId{0},OrganizerId{1}",23pair.EventId,24pair.OrganizerId);25}2627varevsorg2=context.Events28.SelectMany(e=>e.Organizers,29(ev,org)=>new{ev.EventId,org.OrganizerId});30Console.WriteLine("\nUsingSelectMany()");31foreach(varpairinevsorg2)32{33Console.WriteLine("EventId{0},OrganizerId{1}",34pair.EventId,pair.OrganizerId);35}36}代码清单6-1的输出如下:

Usingnestedfromclauses...EventId31,OrganizerId87EventId32,OrganizerId88UsingSelectMany()EventId31,OrganizerId87EventId32,OrganizerId88原理

在数据库中,链接表是表示两张表间多对多关系的通常做法。因为它除了定义两张表间的关系之外,就没有别的作用了,所以实体框架使用一个多对多关联来表示它,不是一个单独的实体。

Event和Organizer间的多对多关联,允许你从Event实体简单地导航到与它关联的organizers,从Organizer实体导航到所有与之关联的events。然而,你只想获取链接表中的外键,这样做,可能是因为这些键有它自身的含义,或者你想使用这些外键来操作别的实体。这里有一个问题,链接表没有被表示成一个实体,因此直接查询它,是不可能的。在代码清单6-1中,我们演示了两种方式来获取底层的外键,不需要实例化关联两边的实体。

第一种方法是,使用嵌套的from从句来获取organizers和它们的每一个event。使用Event实体对象上的导航属性Organizers,并凭借底层的链接表来枚举每个event上的所有organizers。我们将结果重塑到包含两个实体键属性的匿名对象中。最后,我们枚举结果集,并在控制台中输出这一对实体键。

第二中方法是,我们使用SelectMany()方法,投影organizers和他们的每一个event到,包含实体对象envets和organizers的键的匿名对象中。和嵌套的from从句一样,通过导航属性Organizers使用数据库中链接表来实现。并使用与第一种方法一样的方式来枚举结果集。

你想将链接表表示成一个实体,而不是一个多对多关联。

假设在你的数据库中,表Worker和Task之前有一个多对多关系,如图6-3所示。

图6-3表Worker和Task之前有一个多对多关系

WorkerTask表只包含支持多对多关系的外键,再无别的列了。

按下面的步骤,将关联转换成一个代表WorkerTask表的实体:

1、创建一个POCO实体类WorkerTak,如代码清单6-2所示;

2、使用类型为ICollection的属性WorkerTasks替换POCO实体Worker的属性Tasks;

3、使用类型为ICollection的属性WorkerTasks替换POCO实体Task的属性Workers;

4、在上下文对象DbContext的派生类中添加一个类型为DbSet的属性;

最终模型如代码清单6-2所示。

代码清单6-2.包含WorkerTask的最终数据模型

1[Table("Worker",Schema="Chapter6")]2publicclassWorker3{4[Key]5[DatabaseGenerated(DatabaseGeneratedOption.Identity)]6publicintWorkerId{get;set;}7publicstringName{get;set;}89[ForeignKey("WorkerId")]10publicvirtualICollectionWorkerTasks{get;set;}11}1213[Table("Task",Schema="Chapter6")]14publicclassTask15{16[Key]17[DatabaseGenerated(DatabaseGeneratedOption.Identity)]18publicintTaskId{get;set;}1920[Column("Name")]21publicstringTitle{get;set;}2223[ForeignKey("TaskId")]24publicvirtualICollectionWorkerTasks{get;set;}25}2627[Table("WorkerTask",Schema="Chapter6")]28publicclassWorkerTask29{30[Key]31[Column(Order=1)]32publicintWorkerId{get;set;}3334[Key]35[Column(Order=2)]36publicintTaskId{get;set;}3738[ForeignKey("WorkerId")]39publicvirtualWorkerWorker{get;set;}4041[ForeignKey("TaskId")]42publicvirtualTaskTask{get;set;}43}原理

在应用程序开发生命周期中,开发人员经常会在最开始的无载荷多对多关联上增加一个载荷。在本节中,我们演示了如何将一个多对多关联表示为一个单独的实体,以方便添加额外的标量属性。

很多开发人员认为,多对多关联最终都会包含载荷,于是他们为链接表创建了一个合成键(synthetickey),来代替传统的外键构成的组合键(compositekey)形式。

下面是我们的新模型,已经没有一个简单的方式来导航多对多关联。新模型中是两个一对多的关联,这需要增加一级,链接实体。代码清单6-3演示了插入和查询需要增加的额外工作。

代码清单6-13.插入和获取Task和Worker实体

1using(varcontext=newRecipe2Context())2{3context.Database.Log=content=>Debug.Print(content);4varworker=newWorker{Name="Jim"};5vartask=newTask{Title="FoldEnvelopes"};6varworkertask=newWorkerTask{Task=task,Worker=worker};7context.WorkerTasks.Add(workertask);8task=newTask{Title="MailLetters"};9workertask=newWorkerTask{Task=task,Worker=worker};10context.WorkerTasks.Add(workertask);11worker=newWorker{Name="Sara"};12task=newTask{Title="BuyEnvelopes"};13workertask=newWorkerTask{Task=task,Worker=worker};14context.WorkerTasks.Add(workertask);15context.SaveChanges();16}1718using(varcontext=newRecipe2Context())19{20Console.WriteLine("WorkersandTheirTasks");21Console.WriteLine("=======================");22foreach(varworkerincontext.Workers)23{24Console.WriteLine("\n{0}'stasks:",worker.Name);25foreach(varwtinworker.WorkerTasks)26{27Console.WriteLine("\t{0}",wt.Task.Title);28}29}30}代码清单6-3输出如下:

WorkersandTheirTasks=======================Jim'stasks:FoldEnvelopesMailLettersSara'stasks:BuyEnvelopes

你有一张自引用的多对多关系的表,你想为这张表及它的关系建模。

假设你的表拥有一个使用链接表的自引用有关系,如图6-4所示。

图6-4一个与自己多对多的关系表

按下面的步骤为此表建模:

1、在你的项目中创建一个继承自DbContext的类Recipe3Context;

2、使用代码清单6-4中的代码,在你的项目中添加一个POCO实体类Product;

代码清单6-4.创建一个POCO实体类Product

1[Table("Product",Schema="Chapter6")]2publicclassProduct3{4publicProduct()5{6RelatedProducts=newHashSet();7OtherRelatedProducts=newHashSet();8}910[Key]11[DatabaseGenerated(DatabaseGeneratedOption.Identity)]12publicintProductId{get;set;}13publicstringName{get;set;}14publicdecimalPrice{get;set;}1516//自己(本product)的关联Products17publicvirtualICollectionRelatedProducts{get;set;}1819//与自己(本product)关联的Products20publicvirtualICollectionOtherRelatedProducts{get;set;}2122}3、在上下文对象Recipe3Context中添加一个类型为DbSet的属性;

4、在Recipe3Context中重写上下文对象DbContext的方法OnModelCreating,创建自引用的多对多关系映射,如代码清单6-5所示。

代码清单6-5.重写上下文对象DbContext的方法OnModelCreating,创建自引用的多对多关系映射

1protectedoverridevoidOnModelCreating(DbModelBuildermodelBuilder)2{3base.OnModelCreating(modelBuilder);45modelBuilder.Entity()6.HasMany(p=>p.RelatedProducts)7.WithMany(p=>p.OtherRelatedProducts)8.Map(m=>9{10m.MapLeftKey("ProductId");11m.MapRightKey("RelatedProductId");12m.ToTable("RelatedProduct","Chapter6");13});14}原理

正如你看到的那样,实体框架很容易就支持了一个自引用的多对多关联。我们在Product类中创建了两个导航属性,RelatedProducts和OtherRelatedProducts,并在DbContext的派生类中将其映射到底层的数据库中。

代码清单6-6,插入与获取一些关联的products。为了获取给定Product的所有关联Products,我们遍历了两导航属性RelatedProducts和OtherelatedProducts。

代码清单6-6.获取关联产品

using(varcontext=newRecipe3Context()){varproduct1=newProduct{Name="Pole",Price=12.97M};varproduct2=newProduct{Name="Tent",Price=199.95M};varproduct3=newProduct{Name="GroundCover",Price=29.95M};product2.RelatedProducts.Add(product3);product1.RelatedProducts.Add(product2);context.Products.Add(product1);context.SaveChanges();}using(varcontext=newRecipe3Context()){varproduct2=context.Products.First(p=>p.Name=="Tent");Console.WriteLine("Product:{0}...{1}",product2.Name,product2.Price.ToString("C"));Console.WriteLine("RelatedProducts");foreach(varprodinproduct2.RelatedProducts){Console.WriteLine("\t{0}...{1}",prod.Name,prod.Price.ToString("C"));}foreach(varprodinproduct2.OtherRelatedProducts){Console.WriteLine("\t{0}...{1}",prod.Name,prod.Price.ToString("C"));}}代码清单6-6的输出如下:

Product:Tent...$199.95RelatedProductsGroundCover...$29.95Pole...$12.97

在代码清单6-6中,只获取第一层的关联产品。传递关系(transitverelationship)是一个跨越了多层的关系,像一个层次结构。如果我们假设“关联产品(relatedproducts)"关系是可传递的,那么,我们可能需要使用传递闭包(transitiveclosure)形式(译注:这个概念有点绕,大家仔细理解。传递闭包、即在数学中,在集合X上的二元关系R的传递闭包是包含R的X上的最小的传递关系。例如,如果X是(生或死)人的集合而R是关系“为父子”,则R的传递闭包是关系“x是y的祖先”。再比如,如果X是空港的集合而关系xRy为“从空港x到空港y有直航”,则R的传递闭包是“可能经一次或多次航行从x飞到y”)。无论有多少层,传递闭包都将包含所有的关联产品。在电商务应用中,产品专家创建第一层的关联产品,额外层级的关联产品可以通过传递闭包推导出来。最终的结果是,这些应用在你处理订单时会有类似这样的提示“……你可能感兴趣的还有……”。

在代码清单6-7中,我们使用递归方法来处理传递闭包。在遍历导航属性RelatedProducts和OtherrelatedProduxts时,我们要格外小心,不要陷入一个死循环中。如果产品A关联产品B,然后产品B又关联产品A,这样,我们的应用就会陷入无限递归中。为了阻止这种情况的发生,我们使用一个Dictionary<>来帮助我们处理已遍历过的路径。

代码清单6-7.关联产品关系的传递闭包

在代码清单6-7中,我们使用Load()方法(见第五章)来确保关联产品的集合被加载。不幸的是,这意味着,将会有更多的数据库交互。我们可能会想到,预先从Product表中加载出所有的行,并希望Relationshipspan(关联建立)能帮我们建立好关联。但是,Relationshipspan不会为实体集合建立关联(译注:导航属性为集合的情况),只会为实体引用建议关联。因为我们的关系是多对多(实体集合),所以,我们不能依靠relationshipspan来帮我们解决这个问题,只能依靠Load()方法。

代码清单6-7的输出如下。代码块的第一部分,插入关系,我们可以看到,Pole关联Ten,Ten关联GroundCover。Pole的关联产品的传递闭包包含,Ten,GroudCover,和Pole。Pole被包含的原因是,它在Pole与Ten的关系中的另一端。

ProductsrelatedtoPoleTentGroundCoverPole

这一篇讲了三个主题,内容有点多,第三个主题的内容又有点绕,翻译时也费了不少脑力。感谢你阅读。下篇再见!

THE END
1.英语词汇recipe怎么读,是什么意思,单词翻译读音固定搭配用法英汉双解词典包含38652条英汉词条,基本涵盖了全部常用单词的翻译及用法,是英语学习的有利工具。http://ec.newdu.com/28116.html
2.simplified* 在设计领域,可能会提到“simplified design”,意为简化的设计。 * 在技术方面,可能会提到“simplified software”,指的是软件被简化以便于使用。 * 在日常生活中,人们可能会说“I use a simplified version of the recipe”,意思是他们使用了一个简化版的食谱。 http://zixun.thjunshi.com/kjhl/202411/2275776.html
3.RECIPE中文(繁体)翻译:剑桥词典I neverfollowrecipesexactlywhen Icook- I just use them asroughguides. I'm always on thelookoutforinterestingnew recipes. 习语 be a recipe for disaster, trouble, success, etc. (recipe在剑桥英语-中文(繁体)词典的翻译 ? Cambridge University Press) https://dictionary.cambridge.org/zhs/%E8%AF%8D%E5%85%B8/%E8%8B%B1%E8%AF%AD-%E6%B1%89%E8%AF%AD-%E7%B9%81%E4%BD%93/recipe
4.recipes是什么意思recipes在线翻译英语读音用法例句recipes 英['res?p?z]美['res?p?z] 配方 Created with Highcharts 3.0.2释义常用度分布图海词统计 配方 recipes的英文翻译是什么意思,词典释义与在线翻译: 英英释义 名词recipe: directions for making something recipes的用法和样例: 例句http://dict.cn/recipes
5.翻译'recipes'–字典中文加 在上下文、翻译记忆库中将“recipes"翻译成 中文 变形 干 And you see these recipes on the side? 你们注意到旁边这些食谱了吗? ted2019 * Look for a simple recipe that brings swift results. *选择一个做法简单、收效快捷的食谱。 jw2019 In his last report to the General Assembly (https://glosbe.com/en/zh/recipes
6.recipes是什么意思,recipes怎么读,recipes翻译为:烹饪法(reciprecipes的中文意思:烹饪法( recip,点击查看详细解释:recipes的中文翻译、recipes的发音、音标、用法和双语例句等,让你有效掌握recipes这个单词。https://fy.tingclass.net/w/recipes
7.Recipes的翻译是:食谱中文翻译英文意思,翻译英语Recipes 青云英语翻译 请在下面的文本框内输入文字,然后点击开始翻译按钮进行翻译,如果您看不到结果,请重新翻译! 翻译结果1翻译结果2翻译结果3翻译结果4翻译结果5 翻译结果1复制译文编辑译文朗读译文返回顶部 食谱 翻译结果2复制译文编辑译文朗读译文返回顶部http://eyu.zaixian-fanyi.com/fan_yi_4176220
8.recite是什么意思recite怎么读中文意思用法recite recite是什么意思、recite怎么读 读音:英[r?'sa?t] 美[r?'sa?t] 初中高中四级六级考研雅思 recite 基本解释 vt.& vi. 背诵;叙述;列举 vt. 详述,列举;吟诵 vi. 背诵;叙述 recite 词性变化 现在分词:reciting 过去式:recited 过去分词:recited 第三人称单数:reciteshttps://danci.gjcha.com/recite.html
9.recipes的意思是什么recipes中文翻译recipes 历史记录 recipes 双语例句 更多例句 1、 recipesfor jams and preserves 果酱和蜜饯的制作方法 《牛津高阶英汉双解词典》 2、 We produce our own hair-care products, all based on herbalrecipes. 我们自己生产护发产品,全部采用草本配方. 柯林斯词典例句库https://dict.ruihongw.com/recipes
10.recipes的意思recipes翻译recipes用法例句recipes的用法例句英语词典推荐学习词条 英汉词典常见短词用法 字谜推荐 | 笑话推荐 | 对联 | 造句 爱好旅游(打一成语) 年初一晚上打一节目名称 元宵节灯谜:元宵前后共团圆 (打一字) 老赵一走开,完全就变样 (打一食品) 茅台汾酒五粮液,生产流程一样精 (打一成语) 初秋统计,多出一半 (打一字) 意中人伴有https://www.chazidian.com/juzi/recipes/
11.recipes是什么意思recipes的中文翻译例句用法中文翻译 n.烹饪法( recipe的名词复数 );食谱;方法;秘诀 词态变化 原级:recipe 词组短语 healthyrecipes健康食谱 swizzle drinkrecipes调酒秘方 holidayrecipes节日食谱 vegetarianrecipes素食食谱 numericalrecipes数值分析方法库 用法例句 1. Many of theserecipesare highly flavoured. https://danci.gei6.com/recipes__h3rs9joq.html
12."recipes"是什么意思"recipes"翻译recipes ['resipi] n. 食谱;[医]处方;秘诀 同义词 n. formula 参考例子 1.Do you have any good healthy recipes? 有谁知道什么好时髦饮食谱? 2.I hope these recipes will bring you good appetite and health. 希望本书能为大家带来好胃口及身体健康。 3.Most of these are ingredients which are http://mdict.kekenet.com/obedience?word=recipes
13.recipes是什么意思recipes的翻译记忆用法托福例句雅思威学在线词典,为您提供recipes的中文意思,recipes的用法讲解,recipes的读音,recipes的同义词,recipes的反义词,recipes的例句等英语服务。https://t.weixue100.com/word/recipes
14.casualrecipes的中文翻译汉语译词专业词典学术词典casual recipes怎么翻译, 它的中文翻译、汉语译词,岩石的相关专业术语翻译, 来自SCIdict赛斯专业词典的翻译, SCIdict是专为学术研究人员以及技术专家设计的中英专业术语搜索词典,致力于为细分专业领域的翻译提供参照, 并同时促进各行各业人士的专业汉语学习进阶。https://www.scidict.org/items/casual%20recipes.html
15.词汇“simplerecipes”的读音翻译用法及例句simple recipes发音 意思翻译 单方;简易食谱 相似词语短语 simple recipe───单方;简易食谱 simple machines───[机]简单机械 simple device───简单设备 simple tenses───简单时态 simple times───单拍子 simple fractions───[数]简分数 simple fractures───单纯骨折(断骨未刺穿皮肤) http://www.frnht.com/59557.html
16.FoundfreeAIsoftware搜狗翻译andRecipesByAI搜狗翻译 VS Recipes By AI 搜狗翻译 No Rating Yet Sogou Translate, a multilingual translation AI assistant. Recipes By AI 4.5Points Generate customized recipes based on provided ingredients, making it easy for you to start cooking. Traffic Overview https://www.ai-apps.com.cn/contrastproduct?id=d6b2ce7fe280472fb24d79be7efd0cc5&id2=b621f2822aff4609873deea59685d6c7
17.EntityFramework6Recipes(中文word翻译版)资源《 Entity Framework 6 Recipes 》中文翻译系列 (1) --- 第一章 开始使用实体框架之历史和框架简述 《 Entity Framework 6 Recipes 》中文翻译系列 (2) --- 第一章 开始使用实体框架之使用介绍 《 Entity Framework 6 Recipes 》中文翻译系列 (3) --- 第二章 实体数据建模基础之创建一个简单的模型 https://download.csdn.net/download/flyerboy/10425894
18.NaturalHarvestAcollectionofSemen陕西省城镇企业职工基本养老保险注销登记表盖章单位编号:单位名称(章): 年 月 日社会保险登记证编号批准注销、解散等文件名称批准日期注销原因 注销营业执照 ( ) 吊销营业执照 ( ) Natural Harvest - A collection of Semen-Based Recipes外文翻译 来自淘豆网www.taodocs.com转载请标明出处.https://www.taodocs.com/p-22659275.html
19.英语diaphoreticrecipes的翻译音标读音用法例句词典翻译有道精品课云笔记惠惠更多产品 登录 有道- 网易旗下搜索 中英▼ 目录 释义 go top diaphoreticrecipes网络释义 解表剂 diaphoreticfunction发汗机能 diaphoreticrecipes解表剂 diaphoreticvolume发汗量 基于2个网页-相关网页应用推荐https://dict.youdao.com/w/diaphoreticrecipes/
20.《EntityFramework6Recipes》中文翻译系列(28)翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇 5-11 测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经加载到上下文中,另外你想使用Code-First来管理数据访问。 解决方案 假设你有如图5-26所示的概念模型 https://www.pianshen.com/article/8480589481/
21.recipesforjamsandpreserves是什么意思在线翻译recipes for jams and preserves的意思是:果酱和蜜饯的制作方法http://www.hanyucidian.cn/sentence/E153100.html
22.recipe是什么意思音标翻译成中文用法举例词典中文recipe 英语 翻译配方 英式: [?res?pi]美式: [?res?pi] 单词用法: recipe 在不同场景下,可译为: 烹饪法,食谱,方法,秘诀,诀窍 的意思。 n. 名词 1、方法 2、秘诀 3、诀窍 4、食谱 5、烹饪法单词读音: 您的浏览器不支持 video 标签。 双语例句:https://www.3-eee.net/dictionary/ce9c1e9252e6e3da/
23.英语词汇“recipes”的读音翻译释义用法及例句in–house in–law in–line in–service iodic iodide iodides青年旅行网英语在线翻译词典收录了86352条英语词汇在线翻译词条,基本涵盖了全部常用英语词汇的中英文双语翻译及用法,是英语学习的有利工具。Copyright ? 2000-2024 Qntrip.com All Rights Reserved京ICP备2021023879号 更新时间:2024/5/25 18:15:50http://www.qntrip.com/56696.html