请考虑以下事项:
public class Foo
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Something { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Something { get; set; }
[ForeignKey("Foo")]
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
}
现在,在我的上下文中,我希望为相关Foo
s种下一些Bar
:
context.Foos.AddOrUpdate(
r => r.Name,
new Foo
{
Name = "Foo 1",
Something = "Blah",
Bars = new List<Bar>
{
new Bar { Name = "Foo 1 Bar 1", Something = "Blah" },
new Bar { Name = "Foo 1 Bar 2", Something = "Blah" },
new Bar { Name = "Foo 1 Bar 3", Something = "Blah" },
}
},
...
如果我运行Update-Database
,一切都会按照您的预期进行,并且我会为每个Bar
添加相关的Foo
。
现在,如果我将种子数据更改为:
context.Foos.AddOrUpdate(
r => r.Name,
new Foo
{
Name = "Foo 1",
Something = "BlahBlahBlah",
Bars = new List<Bar>
{
new Bar { Name = "Foo 1 Bar 1", Something = "BlahBlahBlah" },
new Bar { Name = "Foo 1 Bar 2", Something = "BlahBlahBlah" },
new Bar { Name = "Foo 1 Bar 3", Something = "BlahBlahBlah" },
}
},
...
再次运行Update-Database
,Foo
会更新,但所有Bar
仍然会有&#34; Blah&#34;他们的Something
属性。这是有道理的,因为实体框架没有逻辑方法知道应该更新哪个Bar
,但有没有解决方法?也许我可以通过其他方式添加Bar
并将它们与Foo
s相关联?我知道我可以做到:
context.Bars.AddOrUpdate(
r = r.Name,
new Bar
{
...
},
...
但鉴于我使用标识列作为键,我无法知道将Bar
添加到哪个Foo
。有什么想法吗?
答案 0 :(得分:1)
第一种方法(问题)和第二种方法(答案)都不适用于第二次执行Seed方法。
第一种方法
Bars = new List<Bar>
{
new Bar { Name = "Foo 1 Bar 1", Something = "Blah" },
// new Bar { Name = "Foo 1 Bar 4", Something = "Blah" },
}
如果您已知第二次执行Seed方法,如果将Something
修改为BlahBlahBlah
,结果将不会保存修改后的Bars
集合,因为它只更新{的标量属性{1}}
首次执行Foo
时,Seed
是一个新实体,此图表下方的所有对象也会被标记为Foo
。
此外,如果在第二次执行Seed方法时,您添加了引用现有Added
的新Bar
(注释代码),则新Foo
也不会被添加。
第二种方法
Bar
这比第一种方法更糟糕,第二次执行Seed方法会抛出异常,因为在更新任何var bar1 = new Bar { Name = "Foo 1 Bar 1", Something = "Blah" };
context.Bars.AddOrUpdate(
r => r.Name,
bar1
);
context.Foos.AddOrUpdate(
r => r.Name,
new Foo
{
Name = "Foo 1",
Something = "Blah",
Bars = new List<Bar>
{
bar1
}
}
);
时,它会尝试更新Bar
与未找到{{}的关系1}},Bar
未指定,表示其值为0. Foo
,其中Id等于0未找到。
<强>解决方案强>
您需要定义临时密钥才能正确执行“添加或更新”。
Bar's FooId
第二次执行种子方法会将Foo
更新为var bar1 =
new Bar { Id = 1, Name = "Foo 1 Bar 1", Something = "Blah", FooId = 1 };
var bar2 =
new Bar { Id = 2, Name = "Foo 1 Bar 2", Something = "Blah", FooId = 1 };
var bar3 =
new Bar { Id = 3, Name = "Foo 1 Bar 3", Something = "Blah", FooId = 1 };
// var bar4 =
// new Bar { Id = 4, Name = "Foo 1 Bar 4", Something = "Blah", FooId = 1 };
db.Bars.AddOrUpdate(
r => r.Name,
bar1,
bar2,
bar3
// bar4
);
db.Foos.AddOrUpdate(
r => r.Name,
new Foo
{
Id = 1,
Name = "Foo 1",
Something = "Blah"
}
);
。新的foo's and Bars' Something
(评论代码)将成功添加,并引用现有的BlahBlahBlah
。
更多
答案 1 :(得分:0)
当我输入问题时,我发现我可以这样做:
var bar1 = new Bar { Name = "Foo 1 Bar 1", Something = "Blah" };
var bar2 = new Bar { Name = "Foo 1 Bar 2", Something = "Blah" };
var bar3 = new Bar { Name = "Foo 1 Bar 3", Something = "Blah" };
...
context.Bars.AddOrUpdate(
r => r.Name,
bar1,
bar2,
bar3,
...
);
context.Foos.AddOrUpdate(
r => r.Name,
new Foo
{
Name = "Foo 1",
Something = "Blah",
Bars = new List<Bar>
{
bar1,
bar2,
bar3
}
},
...
);
然而,我还没有机会对此进行测试,而且无论如何,我仍然对其他想法持开放态度。