2014-09-03 2 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; } 
} 

Теперь в моем контексте, я хочу посеять некоторые 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 s для каждого 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 s обновляется, но все Bar с еще будет «Бла» для их Something Недвижимость. Это имеет смысл, поскольку для Entity Framework нет логичного способа узнать, какой Bar должен быть обновлен, но есть ли какое-либо обходное решение? Возможно, каким-то другим способом я могу добавить Bar s, а также сохранить их связанными с Foo s? Я знаю, что я мог бы просто сделать:

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

Но, учитывая, что я использую столбцы идентификации в качестве ключей, у меня нет никакого способа знать, какие Bar s добавить к какому Foo s. Есть идеи?

ответ

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 коллекцию, потому что он обновляет только скалярные свойства Foo

При первом выполнении Seed, Foo является новой сущностью, и все объекты под этим графом будут помечены как Added тоже.

Кроме того, если на втором выполнении метода Seed, вы добавляете новый 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 
     } 
    } 
); 

Это хуже, чем первый метод, то второе выполнение метода Seed выбросит исключение, потому что при обновлении любого Bar, он будет пытаться обновить отношения Bar к ип -found Foo, Bar's FooId не указывается, что означает, что его значение будет 0. Foo с идентификатором равным 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" 
    } 
); 

Второе исполнение метода Seed будет обновлять foo's and Bars' Something к BlahBlahBlah. И новый 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 
     } 
    }, 
    ... 
); 

Однако, у меня не было возможности проверить это еще, и я до сих пор открыты для другие идеи, независимо.

Смежные вопросы