Csharp/C#教程:如何使用EF6更新多对多表分享


如何使用EF6更新多对多表

我有两节课:

public partial class ObjectiveDetail { public ObjectiveDetail() { this.SubTopics = new List(); } public int ObjectiveDetailId { get; set; } public int Number { get; set; } public string Text { get; set; } public virtual ICollection SubTopics { get; set; } } public partial class SubTopic { public int SubTopicId { get; set; } public string Name { get; set; } } 

我有一个来自用户的ObjectiveDetail对象:

 var web = { "objectiveDetailId":1, "number":1, "text":"datafromweb", "subTopics":[ {"subTopicId":1, "name":"one" }, {"subTopicId":3, "name":"three", } ] } 

以及数据库中的ObjectiveDetail:

 var db = { "objectiveDetailId":1, "number":1, "text":"datafromdb", "subTopics":[ {"subTopicId":1, "name":"one" }, {"subTopicId":2, "name":"two", } ] } 

使用Entity Framework 6,我知道我可以使用以下命令更新ObjectiveDetail类中的文本:

 _uow.ObjectiveDetails.Update(web)); 

但是如何在连接这两个表的多对多表中更新对ObjectiveDetail和SubTopics的引用。 这里例如我想要它,以便对于ObjectiveDetail 1,将many-many更改为引用subTopicId 1和3而不是值1和2.请注意,ObjectiveDetail和SubTopic存储在表中,并且它们之间有另一个表。 这是DDL:

 CREATE TABLE [dbo].[ObjectiveDetail] ( [ObjectiveDetailId] INT IDENTITY (1, 1) NOT NULL, [Text] NVARCHAR (MAX) NOT NULL, [ObjectiveTopicId] INT NULL, CONSTRAINT [PK_ObjectiveDetail] PRIMARY KEY CLUSTERED ([ObjectiveDetailId] ASC), ); CREATE TABLE [dbo].[ObjectiveTopic] ( [ObjectiveDetailId] INT NOT NULL, [SubTopicId] INT NOT NULL, CONSTRAINT [FK_ObjectiveTopicObjectiveDetail] FOREIGN KEY ([ObjectiveDetailId]) REFERENCES [dbo].[ObjectiveDetail] ([ObjectiveDetailId]), CONSTRAINT [FK_ObjectiveTopicSubTopic] FOREIGN KEY ([SubTopicId]) REFERENCES [dbo].[SubTopic] ([SubTopicId]) ); CREATE TABLE [dbo].[SubTopic] ( [SubTopicId] INT IDENTITY (1, 1) NOT NULL, [Name] NVARCHAR (150) NOT NULL, CONSTRAINT [PK_SubTopic] PRIMARY KEY CLUSTERED ([SubTopicId] ASC), ); 

这是我的EF Mapping:

 public class ObjectiveDetailMap : EntityTypeConfiguration { public ObjectiveDetailMap() { // Primary Key this.HasKey(t => t.ObjectiveDetailId); // Relationships this.HasMany(t => t.SubTopics) .WithMany(t => t.ObjectiveDetails) .Map(m => { m.ToTable("ObjectiveTopic"); m.MapLeftKey("ObjectiveDetailId"); m.MapRightKey("SubTopicId"); }); } } 

我认为您正在尝试模拟为您的用户工作的离线模式。 因此,当您从用户那里获得某些内容时,您希望将数据库与用户数据同步。 我做了一个例子,并将你的问题超越了一步:)我添加了一个需要在数据库中更新的Subtopic。 好的,这里是代码:

 static void Main(string[] args) { //the database var ObjectiveDetails = new List() { new ObjectiveDetail() { ObjectiveDetailId = 1, Number = 1, Text = "datafromdb", SubTopics = new List() { new SubTopic(){ SubTopicId = 1, Name="one"}, //no change new SubTopic(){ SubTopicId = 2, Name="two"}, //to be deleted new SubTopic(){ SubTopicId = 4, Name="four"} //to be updated } } }; //the object comes as json and serialized to defined object. var web = new ObjectiveDetail() { ObjectiveDetailId = 1, Number = 1, Text = "datafromweb", SubTopics = new List() { new SubTopic(){ SubTopicId = 1, Name="one"}, //no change new SubTopic(){ SubTopicId = 3, Name="three"}, //new row new SubTopic(){ SubTopicId = 4, Name="new four"} //must be updated } }; var objDet = ObjectiveDetails.FirstOrDefault(x => x.ObjectiveDetailId == web.ObjectiveDetailId); if (objDet != null) { //you can use AutoMapper or ValueInjecter for mapping and binding same objects //but it is out of scope of this question //update ObjectDetail objDet.Number = web.Number; objDet.Text = web.Text; var subtops = objDet.SubTopics.ToList(); //Delete removed parameters from database //Entity framework can handle it for you via change tracking //subtopicId = 2 has been deleted subtops.RemoveAll(x => !web.SubTopics.Select(y => y.SubTopicId).Contains(x.SubTopicId)); //adds new items which comes from web //adds subtopicId = 3 to the list var newItems = web.SubTopics.Where(x => !subtops.Select(y => y.SubTopicId).Contains(x.SubTopicId)).ToList(); subtops.AddRange(newItems); //this items must be updated var updatedItems = web.SubTopics.Except(newItems).ToList(); foreach (var item in updatedItems) { var dbItem = subtops.First(x => x.SubTopicId == item.SubTopicId); dbItem.Name = item.Name; } //let's see is it working Console.WriteLine("{0}:t{1}t{2}n---------",objDet.ObjectiveDetailId, objDet.Number, objDet.Text); foreach (var item in subtops) { Console.WriteLine("{0}: {1}", item.SubTopicId, item.Name); } } else { //insert new ObjectiveDetail } //In real scenario after doing everything you need to call SaveChanges or it's equal in your Unit of Work. } 

结果:

 1: 1 datafromweb --------- 1: one 4: new four 3: three 

而已。 您可以像这样同步数据库和用户数据。 而AutoMapper和ValueInjecter都是非常有用和强大的工具,我深深建议你看看那些。 我希望你喜欢,快乐编码:)

这是一个方法,它接受目标ObjectiveDetail的ID和要添加到目标ObjectiveDetailSubTopic ID的IEnumerable

 public void UpdateSubTopics( int objectiveDetailId, IEnumerable newSubTopicIds ) { using( var db = new YourDbContext() ) { // load SubTopics to add from DB var subTopicsToAdd = db.SubTopics .Where( st => newSubTopicIds.Contains( st.SubTopicId ) ); // load target ObjectiveDetail from DB var targetObjDetail = db.ObjectiveDetail.Find( objectiveDetailId ); // should check for targetObjDetail == null here // remove currently referenced SubTopics not found in subTopicsToAdd foreach( var cst in targetObjDetail.SubTopics.Except( subTopicsToAdd ) ) { cst.SubTopics.Remove( cst ); } // add subTopicsToAdd not currently found in referenced SubTopics foreach( var nst in subTopicsToAdd.Except( targetObjDetail.SubTopics ) ) { targetObjDetail.SubTopics.Add( nst ); } // save changes db.SaveChanges(); } } 

我首先只使用EF代码,并定义3个表,你要么定义所有3个表,要么只是定义2个表,每个表都有一个集合,就像这样

 public class ObjectiveDetail { public ObjectiveDetail() { this.SubTopics = new HashSet(); } public int ObjectiveDetailId { get; set; } public int Number { get; set; } public string Text { get; set; } public virtual ICollection SubTopics { get; set; } } public partial class SubTopic { public SubTopic() { this.ObjectiveDetail = new HashSet(); } public int SubTopicId { get; set; } public string Name { get; set; } public virtual ICollection ObjectiveDetails { get; set; } } 

如果您有3个表,则可以使用新的ID更新中间表。 您必须获取要更新的所有ObjectiveTopics,并更改ID,然后执行更新

 ObjectiveTopic objectiveTopic = _uow.ObjectiveTopic.Get(1); ObjectiveTopic.SubTopicId = 2; ObjectiveTopic.ObjectiveDetailId = 1; _uow.ObjectiveTopic.Update(objectiveTopic); 

如果您没有将第三个表定义为实体,并且您只能访问ObjectiveDetail和SubTopic表,那么您可以获取两个实体并删除不再需要的实体,并添加一个你要。

 ObjectiveDetail objectiveD = _uow.ObjectiveDetail.Get(1); SubTopic subTopic = _uow.SubTopic.Get(1); //SubTopic to remove SubTopic topicToAdd = _uow.SubTopic.Get(2); //SubTopic to add ObjectiveDetail.SubTopics.Remove(subTopic); //Remove the entity from the ObjectiveTopic table ObjectiveDetail.SubTopics.Add(topicToAdd); //Add the new entity, will create a new row in ObjectiveTopic Table _uow.ObjectiveDetail.Update(objectiveD); 

如果你想(也许应该),你可以在objectiveD上使用linq从集合中获取实体,而不是从数据库中检索它。

 SubTopic subTopic = objectiveD.SubTopics.Single(x => x.SubTopicId == 1); //Instead of _uow.SubTopic.Get(1); ... 

您可以使用通用方法,以便它可以用于任何多对多关系。 您只需在主对象的多对多集合中提供此整数列表,表示要更新的字段的ID:

 protected void UpdateManyToMany(YourDBContext db, ICollection collection, List idList) where T : class { //update a many to many collection given a list of key IDs collection.Clear(); var source = db.Set(); if (idList != null) { foreach (int i in idList) { var record = source.Find(i); collection.Add(record); } } } 

你会这样称呼它:

上述就是C#学习教程:如何使用EF6更新多对多表分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)

 UpdateManyToMany(db, objectiveDetail.SubTopics, subTopicIDList); 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ctvol.com/cdevelopment/1025034.html

(0)
上一篇 2022年1月8日
下一篇 2022年1月8日

精彩推荐