Это, скорее всего, из-за разрозненных лиц.Каков источник свойств Log & LogFiles?Я предполагаю, что они исходят от веб-клиента?
Чтобы обрисовать проблему с проходящими объектами: Давайте посмотрим на объект Photo, у которого есть ссылка Status.
public class Status
{
public int StatusId { get; set; }
public string Name { get; set; }
}
public class Photo
{
public int PhotoId { get; set; }
public virtual Status Status { get; set; }
}
Теперь, если япойти и загрузить набор фотографий из DbContext. Я мог бы вернуть 2 фотографии со статусом «Новый».
Что касается "экземпляров", у меня было бы:
Photo (ID: 1) \
==> Status (ID: 1 [New])
Photo (ID: 2) /
Проблема в том, что когда я отправляю эти отключенные объекты обратно в нечто вроде контроллера, они десериализуются и будут выглядетьнапример:
Photo (ID: 1) ==> Status (ID: 1 [New])
Photo (ID: 2) ==> Status (ID: 1 [New])
В вашем случае вы возвращаете новую фотографию (в порядке), но она должна быть связана с существующим статусом.Ваша сущность Photo, вероятно, будет настроена для создания PK, но поиск типа Status не будет.В любом случае, если EF не «знает» о статусе, он будет рассматриваться как новый объект вместе с фотографией.Это приводит к ограничению FK, поскольку EF пытается вставить идентификатор состояния 1.
Передача сущностей обратно в контроллеры приводит к всевозможным проблемам.Если вы выполняете, например, Редактирование фотографии, возвращая фото ID 1, вы обнаружите, что вам нужно как-то сообщить EF о фотографии # 1 (используя Attach
и, например, установить для параметра «Состояние» значение «Изменено»), а затемтакже сталкиваются с ошибками FK вокруг любых связанных объектов к фотографии.Присоединение связанных сущностей (таких как Status) первоначально решит вашу проблему, но затем приведет к дополнительным сложностям, подобным описанным выше, когда множественные ссылки на один и тот же Status фактически являются отдельными экземплярами объекта Status.Вызов присоединения к первому экземпляру будет работать, но затем вы получите исключение, как только сохраните что-то в этом контексте с тем же статусом.Различные ссылки и EF будут жаловаться на то, что экземпляр с одинаковым идентификатором связан с контекстом, если вы попытаетесь присоединить 2-й.
Присоединение объектов от самого клиента - опасная практика, поскольку вы неявно доверяете поступающим данным.назад от клиента.Опытный, злонамеренный пользователь может легко изменить данные любым количеством способов, помимо того, что позволяет ваша веб-страница, повредив хранилище данных.
Главный совет, который я даю разработчикам в EF, - не передавайте сущности вокруг».Ничего хорошего из этого не выйдет.:) Если вы передадите модели просмотра журнала, модели просмотра фотографий и т. Д., Тогда это сократит объем данных, передаваемых туда и обратно между сервером и клиентом (что делает систему более быстрой и менее ресурсоемкой), и заставляет задуматься о поступлении данных.назад.
Например, если я заберу LogInsertViewModel и набор связанных PhotoInsertViewModels
public async Task<Log> AddAsync(LogInsertViewModel logVm, ICollection<PhotoInsertViewModel> photoVms)
{
// TODO: Validate that the log & files are correct/complete and applicable to the current session user...
// If I need to lookup values from collections... (1 hit to DB to get all applicable)
statusIds = photoVms.Select(x => x.StatusId).ToList();
var statuses = context.Statuses.Where(x => statusIds.Contains(x.StatusId)).ToList();
// Alternatively if I know all new photos were going to be associated a "New" status...
var newStatus = context.Statuses.Single(x => x.Status = Statuses.New);
// Create a Log.
var log = new Log
{
//.. copy values.
Photos = photoVms.Select(x => new Photo
{
// copy values.
Status = statuses.Single(s => s.StatusId = x.StatusId); // or newStatus
}).ToList();
};
context.Logs.Add(log);
context.SaveChanges();
}