2015-01-29 3 views
2

Кажется, я помню (возможно, неправильно), что DLinq предлагал автоматические ассоциации. Кажется, я не могу найти, как включить или выполнить это в EF.Существуют ли автоматические ассоциации в Entity Framework?

Пример:

public partial class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Clan Clan { get; set; } 
} 

public partial class Clan 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Person> People { get; set; } 
} 

Если бы это были мои сущности, то я хотел бы, чтобы выполнить действие, как это:

var p = new Person() { Name = "Tom" }; 
var c = new Clan() { Name = "SomeClan" }; 
p.Clan = c; 
ASSERT(c.People.First() == p) 

или попеременно

var p = new Person() { Name = "Tom" }; 
var c = new Clan() { Name = "SomeClan" }; 
c.People.Add(p); 
ASSERT(p.Clan == c) 

Кроме того, я должен использовали метод c.People.Add, он должен был проверить, есть ли p.Clan уже ссылается на другой клан, и если это так, удаляет его из коллекции людей клана.

В DLINQ я полагал, что они использовали EntitySet и EntityRef для этого. Существует ли эквивалент в Entity Framework?

Большое спасибо!

ответ

4

Я пробовал свой код в LINQ-toSQL (ранее назывался DLINQ), но утверждение никогда не пройдет. Очевидная причина в том, что контекст даже не знает о новых объектах, поэтому он не может их ассоциировать. Тем не менее, даже если вставить объекты в контекст c.People не будет заполняться

var p = new Person() { Name = "Tom" }; 
var c = new Clan() { Name = "SomeClan" }; 
p.Clan = c; 
context.People.InsertOnSubmit(p); 
context.Clans.InsertOnSubmit(c); 
ASSERT(c.People.First() == p) // Still no items in c.People 

И даже после того, как SubmitChanges, c.People не имеет элементов. Только при повторном извлечении нового Clan из базы данных в новом контексте c.People будет загружен ленивой загрузкой. Таким образом, эти «автоматические ассоциации» не существуют в LINQ-to-SQL.

В инфраструктуре Entity существует процесс, называемый взаимосвязь коррекции, которая работает very frequently. В этом процессе EF просматривает значения первичного и внешнего ключей и заполняет навигационные свойства (например, c.People), когда они совпадают.

Если вы делаете то же самое в EF:

var p = new Person() { Name = "Tom" }; 
var c = new Clan() { Name = "SomeClan" }; 
p.Clan = c; 
context.People.Add(p); // Also adds c to the context 

... метод Add вызовет DetectChanges, который, в свою очередь, запускает отношения FixUp и

ASSERT(c.People.First() == p) 

... теперь проходить.

+0

Это то, чего я боялся, но хорошо знать, что Fixup происходит на Добавить. Что касается DLINQ, я полностью согласен с тем, что использование класса «POCO» не будет иметь ничего. Однако, если вы использовали класс, сгенерированный диаграммой модели, он использовал бы «EntitySet » и «EntityRef » вместо ICollection и Clan. Таким образом, за счет отсутствия класса POCO, я думаю, что эти два класса «прокси» были там, где произошло исправление. Но, несмотря на это, ваш ответ поражает гвоздь по голове тем, что мне нужно делать. СПАСИБО! – Veldaeven

0

Было бы много способов сделать это. Проще всего было бы добавить ClanId свойства к классу Person, а затем использовать это:

public partial class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int ClanId {get; set;} // You might need to make it virtual. Not sure. 
    public virtual Clan Clan { get; set; } 
} 

public partial class Clan 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Person> People { get; set; } 
} 

Это даст указание EF для создания внешнего ключа по имени ClanId. Тогда вы могли бы использовать следующий синтаксис:

var p = new Person() { Name = "Tom" }; 
var c = new Clan() { Name = "SomeClan" }; 
p.ClanId = X; // Replace X by a suitable Id. 
ASSERT(c.People.First() == p) 

Идея заключается в том, чтобы убедиться, что ключ иностранных отношений создаются правильно. EF может сделать вывод, что много раз, особенно в отношениях от одного до многих, но есть случаи, когда это не так. Явным образом указывая его так, он будет работать во всех случаях.

Это также имеет дополнительные преимущества, когда вы пытаетесь связать нового человека с существующим кланом. В некоторых случаях EF считает, что клан является новым и пытается его вставить. При таком подходе вы не столкнетесь с этой проблемой.

Другим способом было бы явно указать отношение внешних ключей в переопределенном методе OnModelCreating.

+0

Это не сработает. Ваше решение отлично работает, когда вы находитесь в рамках DbContext и вызывается SaveChanges(). Если я сделаю присвоение 'p.Clan = c' в области« использования »DbContext, выполните« SaveChanges() »в DbContext, откройте новую область с помощью нового DbContext. Ссылки все там и отлично , Однако в вашем примере, даже с добавлением Id и ClanId, ASSERT терпит неудачу: если вся операция выполняется за пределами области использования DbContext_ – Veldaeven