Первый Кодекс: Независимые ассоциации против Ассоциаций иностранных ключей? - PullRequest
100 голосов
/ 12 марта 2011

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

Ассоциация внешнего ключа

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; } // <-- Customer ID
    ...
}

В отличие от независимых ассоциаций :

Независимая ассоциация

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

В прошлом я работал с NHibernate и использовал независимые ассоциации, которые не только чувствуют себя более неестественно, но и (с ленивой загрузкой) имеют преимущество, давая мне доступ ко всему объекту Customer, а не только к его ID. Это позволяет мне, например, получить экземпляр Order и затем выполнить Order.Customer.FirstName без явного объединения, что крайне удобно.

Итак, подведем итог, мои вопросы:

  1. Есть ли существенные недостатки в используя независимые ассоциации? и ...
  2. Если их нет, что будет причиной использования ассоциаций внешних ключей вообще?

Ответы [ 4 ]

106 голосов
/ 12 марта 2011

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

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

Как только вы генерируете модель сущности из базы данных с FK, она всегда будет генерировать ссылки на сущности.Если вы не хотите их использовать, вы должны вручную изменить файл EDMX и добавить свойства, представляющие FK.По крайней мере, это имело место в Entity Framework v1, где допускались только независимые ассоциации.

Entity Framework v4 предлагает новый тип ассоциации, называемый Связью внешнего ключа.Наиболее очевидное различие между независимым и внешним ключом связи заключается в классе заказа:

public class Order
{
    public int ID { get; set; }
    public int CustomerId { get; set; }  // <-- Customer ID
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

Как видите, у вас есть и свойство FK, и ссылка на сущность.Существует больше различий между двумя типами ассоциаций:

Независимая ассоциация

  • Она представлена ​​как отдельный объект в ObjectStateManager.Он имеет свой собственный EntityState!
  • При создании ассоциации вам всегда нужны права с обоих концов ассоциации
  • Эта ассоциация отображается так же, как и сущность.

Ассоциация внешнего ключа

  • Не представляется как отдельный объект в ObjectStateManager.В связи с этим вы должны соблюдать некоторые особые правила.
  • При создании ассоциации вам не нужны оба конца ассоциации.Достаточно иметь дочернюю сущность и PK родительской сущности, но значение PK должно быть уникальным.Поэтому при использовании связи с внешними ключами вы также должны назначить временные уникальные идентификаторы вновь создаваемым объектам, используемым в отношениях.
  • Эта связь не отображается, а вместо этого определяет ограничения ссылок.

Если выЧтобы использовать ассоциацию внешнего ключа, необходимо отметить Включить столбцы внешнего ключа в модель в Мастере модели данных сущностей.

Редактировать:

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

33 голосов
/ 13 мая 2011

Используйте оба.И сделайте ваши ссылки на сущности виртуальными, чтобы обеспечить ленивую загрузку.Например:

public class Order
{
  public int ID { get; set; }
  public int CustomerID { get; set; }
  public virtual Customer Customer { get; set; } // <-- Customer object
  ...
}

Это экономит на ненужных поисках БД, позволяет выполнять отложенную загрузку и позволяет легко увидеть / установить идентификатор, если вы знаете, каким он должен быть.Обратите внимание, что наличие обоих никак не меняет структуру вашей таблицы.

8 голосов
/ 18 августа 2014

Независимая ассоциация плохо работает с AddOrUpdate, который обычно используется в методе Seed.Если ссылка является существующим элементом, она будет вставлена ​​повторно.

// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);

В результате существующий клиент будет повторно вставлен, а новый (повторно вставленный) клиент будет связан с новым заказом.


Если мы не используем связь с внешним ключом и не назначаем идентификатор.

 // Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);

У нас ожидаемое поведение, существующий клиент будет связан с новым заказом.

4 голосов
/ 12 марта 2011

Я предпочитаю объектный подход, чтобы избежать ненужных поисков.Объекты свойств могут быть так же легко заполнены, когда вы вызываете ваш фабричный метод для построения всей сущности (используя простой код обратного вызова для вложенных сущностей).Я не вижу никаких недостатков, кроме использования памяти (но вы бы кэшировали свои объекты правильно?).Таким образом, все, что вы делаете, это подставляете стек для кучи и получаете выигрыш в производительности, если не выполнять поиск.Я надеюсь, что это имеет смысл.

...