В чем смысл создания свойств внешнего ключа при использовании Entity Framework Code First?

Просматривая вопросы и ответы на этом сайте и читая некоторые из лучших руководств Google по разработке Code First, я часто вижу следующую картину...

public class Category
{
    public Category()
    {
        Products = new Collection<Product>();
    }
    public Guid ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    public Guid ID { get; set; }
    public string Name { get; set; }
    public DateTime DateAdded { get; set; }
    public Guid CategoryID { get; set; } // Seemingly redundant property
    public virtual Category Category { get; set; }
}

При поиске руководств по Code First появляются следующие две страницы, использующие один и тот же шаблон:

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

http://www.codeproject.com/Articles/327945/Architecture-Guide-ASP-NET-MVC3-Entity-Framework-C

Вопрос. Так какой смысл иметь свойство внешнего ключа для объекта Code First C#? В приведенном выше примере вы можете опустить CategoryID из класса Product, и все будет работать нормально. Внешний ключ Category_ID все равно будет создан в базе данных.

Единственное, что я мог придумать, это то, что люди могли бы захотеть указать, является ли отношение необязательным, используя типы, допускающие значение NULL, вместо плавного API, но я думаю, что наличие свойства Category и CategoryID действительно сбивает с толку.

Итак, прежде чем я пойду и удалю все свои свойства внешнего ключа, есть ли что-то, что я здесь упустил? Какой смысл это делать?

Спасибо!


person Jeff Camera    schedule 12.02.2012    source источник
comment
Я думаю, что сделать его Guid? имеет значение. Могут применяться некоторые аннотации к данным.   -  person Henk Holterman    schedule 13.02.2012
comment
Да, я упомянул об этом в своем вопросе... что-нибудь, что нельзя сделать с помощью свободного API? Кажется довольно злым иметь два по существу повторяющихся свойства, когда вам это не нужно.   -  person Jeff Camera    schedule 13.02.2012


Ответы (1)


Да, я думаю, что в свойствах внешнего ключа нет необходимости, и они являются каким-то реляционным артефактом в мире объектов. Вы можете полностью определить отношения без свойств FK. В Fluent API вы можете определить, является ли отношение необязательным или обязательным, и вы можете указать имя столбца внешнего ключа таблицы базы данных. В таком случае связь называется Независимая ассоциация.

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

Предположим, у вас есть веб-представление для создания или редактирования продукта, и представление содержит поле со списком для выбора категории и назначения ее продукту. Чтобы заполнить поле со списком при отображении представления, вы должны загрузить, например, ID и Name всех категорий из базы данных.

Когда страница будет отправлена ​​обратно, вы получите свойства продукта и ID выбранной категории. Если у вас нет свойства внешнего ключа CategoryID в вашем Product, вам нужно будет создать отношение следующим образом:

var category = new Category { ID = IDFromComboBox };
context.Categories.Attach(category);
product.Category = category;

Со свойством FK вам нужна только одна строка:

product.CategoryID = IDFromComboBox;

Свойства внешнего ключа не существовали в Entity Framework версии 1 (.NET 3.5) и были представлены в EF версии 4 (.NET 4) для лучшей поддержки описанных выше сценариев.

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

http://www.ladislavmrnka.com/2011/05/foreign-key-vs-independent-associations-in-ef-4/

person Slauma    schedule 12.02.2012
comment
Спасибо за подробный ответ и ссылку на блог. Возможно, я что-то упускаю из вашего примера... Если вы заполняете поле со списком категориями из базы данных, а форма отправляется обратно с выбранным идентификатором категории, не попытаетесь ли вы извлечь категорию из базы данных (var category = db.Single(x => x.ID == id);), выполните проверки, а затем назначить категорию, просто перейдя product.Category = category? - person Jeff Camera; 13.02.2012
comment
@JohntheRevelator: Да, это альтернатива. Но это потребовало бы дополнительного обращения к базе данных. Вам не нужен этот обратный путь, если у вас есть идентификатор, для этого и нужен Attach. Однако проверка — это хороший момент, вы имеете в виду проверку, существует ли вообще категория с опубликованным идентификатором, верно? Вы все еще можете сделать это с if (db.Categories.Any(x => x.ID == id)) ..., который просто возвращает bool и будет дешевле, чем возврат полной категории. - person Slauma; 13.02.2012