Да, начните с чтения свойств навигации и сопоставления отношений с EF. Используя эти отношения, EF будет отслеживать, какие сущности зависят от других, чтобы вы могли создать свой граф сущностей, например:
using ( var context = new MyContext())
{
var newBoard = new Board { BoardName = boardName };
var newCity = new City { CityName = cityName, Board = newBoard };
var newChild = new Child { ChildName = childName, City = newCity };
context.Children.Add(newChild);
context.SaveChanges();
}
Когда EF перейдет к фиксации изменений, каждая сущность, сопоставленная со столбцом идентичности, получит свойновый идентификатор, и эти идентификаторы будут автоматически назначаться для FK связанных сущностей.
С EF вам также не нужно выставлять поля FK в ваших сущностях, и рекомендуется избегать раскрытия FK. С EF Core вы можете использовать Shadow Properties для отображения ваших сущностей. Разоблачение FK может привести к проблемам при обновлении. Если ребенок выставляет ссылку на город и свойство CityId FK, и я хочу назначить ему новый город, у меня теперь есть два способа:
child.City = fourthCity;
// or
child.CityId = 4;
Это может привести к непоследовательному поведению и ошибкам в предположениях. ,Например:
var child = context.Children.Find(1); // Child #1 references City #1.
var fourthCity = context.Cities.Find(4);
child.City = fourthCity;
Console.WriteLine(child.City.CityId); // "4"
Console.WriteLine(child.CityId); // "1"
context.SaveChanges();
Console.WriteLine(child.CityId); // Now it's "4"
Любой код, ссылающийся на FK до SaveChanges
, получит старый идентификатор, а код, ссылающийся на идентификатор связанного объекта, получит новый. FK не обновляется до тех пор, пока не будет вызван SaveChanges
.
Изменение FK также может привести к проблемам и ошибкам.
var child = context.Children.Find(1); // Child #1 references City #1.
child.CityId = 4;
Console.WriteLine(child.CityId); // "4"
Console.WriteLine(child.City.CityId); // NullReferenceException! (Lazy load call fails)
Ленивая загрузка (по крайней мере, в EF6)колебание, если вы попытаетесь это сделать. Если вы хотите загрузить город:
var child = context.Children.Include(x => x.City).Single(x => x.ChildId == 1); // Child #1 references City #1.
child.CityId = 4;
Console.WriteLine(child.CityId); // "4"
Console.WriteLine(child.City.CityId); // "1"
Context.SaveChanges();
Console.WriteLine(child.City.CityId); // "4"
Вы столкнетесь с непоследовательным поведением, когда код ссылается на FK и свойства навигации. В некоторых случаях вы можете захотеть, чтобы объекты отображали FK, а не свойства навигации (например, при выполнении операций с большими объемами), поэтому я бы рекомендовал использовать один или другой, но не оба.
Кроме того, избегайте денормализации вашей схемы. Если ребенок связан с городом, а город с правлением, вы можете ссылаться на доску ребенка через свой город, а не указывать BoardID на ребенке.
Т.е. child.City.Board.BoardName
Денормализация проблематична, поскольку нет способа обеспечить соответствие ссылки на доску ребенка его назначенной ссылке на доску города.
Например:
var board1 = context.Boards.Find(1);
var board2 = context.Boards.Find(2);
var child = context.Children.Find(1);
Если идентификатор ребенка № 1 ссылается на идентификатор города №1, которая ссылается на Идентификатор платы № 1, а Child также имеет ссылку на Идентификатор платы № 1, тогда что-то подобное в коде, преднамеренное или по ошибке, может вызвать проблемы в будущем:
child.Board = board2;
Любойкод, ссылающийся на доску ребенка через child.Board.BoardId
, будет возвращать "2", однако любой код, который ссылается на child.City.Board.BoardId
, все равно будет возвращать "1". Подобно проблеме с раскрытием FK на ваших сущностях, эти денормализованные ссылки могут привести к неправильным ссылкам в зависимости от того, куда вы смотрите, за исключением того, что в отличие от проблемы FK, они не разрешаются автоматически при фиксации изменений. Идентификатор доски ребенка и идентификатор доски города, на который она ссылается, не совпадают в данных.