2014-09-03 53 views
1

播种项目考虑以下几点:有关系

现在
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; } 
} 

,在我的背景,我想与相关Bar s到种子一些Foo S:

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一切正常你会期望的,并且我为每个Foo添加了相关的Bar。现在

,如果我去改变我的种子数据是这样的:

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 s的更新,但所有的Bar S的仍会有“嗒嗒”为自己的Something属性。这是有道理的,因为Entity Framework没有合适的方法来知道应该更新哪个Bar,但有没有解决方法?也许我可以通过其他方式添加Bar并将它们与Foo关联?我知道我可以简单地做:

context.Bars.AddOrUpdate(
    r = r.Name, 
    new Bar 
    { 
     ... 
    }, 
    ... 

但考虑到我使用的标识列钥匙,我也没有办法知道哪些Bar s到添加到Foo秒。有任何想法吗?

回答

1

您的第一个方法(问题)和第二个方法(答案)都不适用于第二次执行Seed方法。

第一种方法

Bars = new List<Bar> 
{ 
    new Bar { Name = "Foo 1 Bar 1", Something = "Blah" }, 
    // new Bar { Name = "Foo 1 Bar 4", Something = "Blah" }, 
} 

正如你所知道的种子法的第二次执行,如果修改SomethingBlahBlahBlah结果不会保存修改后的Bars集合,因为它仅更新的Foo标量属性

在第一次执行Seed时,Foo是一个新的实体,该图下的所有对象将被标记为Added

此外,如果在种子法的第二次执行中,添加一个新的Bar(注释代码),指的是现有Foo,新Bar不会太增加。

第二种方法

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时,它会尝试更新的Bar联合国的关系 - 找到Foo,Bar's FooId未指定,表示其值为0. Foo,Id等于0未找到。

解决方案

您需要定义临时键就可以执行“添加或更新”正确。

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' SomethingBlahBlahBlah。并且新的Bar(已注释的代码)将成功添加并参考现有的Foo

更多

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 
     } 
    }, 
    ... 
); 

不过,我还没有机会尚未测试此,我仍然是开放的其他想法,不管。