Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я их добавлю:
Родовые словари в .NET не являются потокобезопасными, а иногда могут бросать NullReference
или даже (чаще) a KeyNotFoundException
при попытке получить доступ к ключу из двух параллельных потоков. Исключение в этом случае является довольно ошибочным.
Если код NullReferenceException
задан кодом unsafe
, вы можете посмотреть на переменные указателя , и проверьте их на IntPtr.Zero
или что-то в этом роде. Это одно и то же («исключение нулевого указателя»), но в небезопасном коде переменные часто переводятся в типы значений / массивы и т. Д., И вы ударяете головой о стену, задаваясь вопросом, как тип значения может исключение.
(Еще одна причина для небезопасного использования небезопасного кода, если вам это нужно)
Если вы хотите в полной мере использовать ORM, вы обязательно будете использовать ссылку Entity:
public class Order
{
public int ID { get; set; }
public Customer Customer { get; set; } // <-- Customer object
...
}
. Когда вы создаете модель сущности из базы данных с помощью FK, она всегда будет генерировать ссылки на сущности. Если вы не хотите их использовать, вы должны вручную изменить файл EDMX и добавить свойства, представляющие FK. По крайней мере, это было в Entity Framework v1, где допускались только независимые ассоциации.
Entity framework v4 предлагает новый тип связи, называемый ассоциацией внешних ключей. Наиболее очевидным различием между независимой и внешней ключевой ассоциацией является класс Order:
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
он не представлен как отдельный объект. В связи с этим вы должны следовать некоторым специальным правилам. Если вы хотите использовать ассоциацию внешних ключей, вы должны отметить Включить столбцы внешнего ключа в модели в Мастере моделей данных сущностей.
Изменить:
Я нашел что разница между этими двумя типами ассоциаций не очень хорошо известна, поэтому я написал короткую статью , в которой подробно описывается это и мое собственное мнение об этом.
Я одобряю объектный подход, чтобы избежать ненужных поисков. Объекты свойств могут быть так же легко заполнены, когда вы вызываете свой заводский метод для построения всей сущности (используя простой код обратного вызова для вложенных объектов). Нет никаких недостатков, которые я вижу, кроме использования памяти (но вы бы кешировали свои объекты правильно?). Таким образом, все, что вы делаете, заключается в замене стека на кучу и повышение производительности из-за неэффективности поиска. Надеюсь, это имеет смысл.
Используйте оба параметра. И сделайте ваши сущности ссылками виртуальными, чтобы обеспечить ленивую загрузку. Например:
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; } // <-- Customer object
...
}
Это избавляет от ненужных поисков БД, позволяет ленивую загрузку и позволяет легко видеть / устанавливать идентификатор, если вы знаете, кем вы хотите. Обратите внимание, что наличие обоих параметров не меняет структуру вашей таблицы.
Независимая ассоциация не работает с 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);
Мы ожидаем, что существующий клиент будет связан с новым порядком.