我有两个类:
public partial class ObjectiveDetail {
public ObjectiveDetail() {
this.SubTopics = new List<SubTopic>();
}
public int ObjectiveDetailId { get; set; }
public int Number { get; set; }
public string Text { get; set; }
public virtual ICollection<SubTopic> 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,将许多更改为引用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映射:
public class ObjectiveDetailMap : EntityTypeConfiguration<ObjectiveDetail>
{
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");
});
}
}
最佳答案
我认为您正在尝试模拟脱机模式为您的用户工作。因此,当您从用户那里得到一些东西时,您希望将数据库与用户数据同步。我举一个例子,将您的问题超越了一步:)我添加了一个子主题,该子主题需要在数据库中进行更新。好的,这是代码:
static void Main(string[] args)
{
//the database
var ObjectiveDetails = new List<ObjectiveDetail>()
{
new ObjectiveDetail()
{
ObjectiveDetailId = 1,
Number = 1,
Text = "datafromdb",
SubTopics = new List<SubTopic>()
{
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<SubTopic>()
{
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都是非常有用且功能强大的工具,我强烈建议您看一看。希望您喜欢,编码愉快:)