Что именно вы подразумеваете под "Есть ли способ обойти это, не перемещая События из своей собственной сущности в CustomerEntities?"Исходя из того, что вы показали, похоже, что вы создаете один DbContext для каждой сущности или для сущности верхнего уровня, которая действительно выделяет неприятный запах, если эти сущности являются частью одной и той же базы данных.DbContext не является сущностью, это контейнер для многих сущностей.Для небольших систем в нем легко размещаются все сущности или, по крайней мере, все сущности верхнего уровня, к которым необходимо обращаться напрямую.«Сущность» - это класс, представляющий строку в таблице в базе данных.
Обычно я ожидаю увидеть это, если вы работаете с календарями и клиентами, где запись календаря ссылается на клиента инабор событий, для которых у меня будет сущность CalendarEntry, похожая на:
public class CalendarEntry
{
public int CalendarEntryId { get; private set; }
// .. Other properties...
public virtual Customer Customer { get; private set; }
public virtual List<CalendarEvent> Events { get; private set; } = new List<CalendarEvent>();
}
С аналогичными определениями сущностей для клиента и событий.
Был бы один единственный DbContext, который мог бы иметь:
public DbSet<CalendarEntry> CalendarEntries { get; }
public DbSet<Customer> Customers { get; }
Модели представления, с другой стороны, являются простыми, классы POCO, чьи данные копируются из сущностей, и не содержат сущности.Контроллер управляет областью действия DbContext для чтения сущностей, затем выбирает или отображает данные сущностей в модели представлений для передачи в представление.Он получает модели представлений из вида, загружает сущности и изменяет сущности на основе данных в модели представлений.
Таким образом, действие, которое получает событие календаря для обновления, я хотел бы получить метод, который бы принялмодель представления для представления нового события календаря, включая идентификатор записи календаря.Запись не будет создаваться в индексе события календаря, а скорее до этого, тогда индекс просто отображает модель представления для новой записи.Поэтому, возможно, на контроллере календаря будет действие для создания нового события, которое передаст CalendarEntryID, создаст модель представления CalendarEvent для записи и затем перенаправит на представление события календаря.ViewModel - это POCO, а не объект, еще ничего не передано в базу данных.В представлении CalendarEvent будет кнопка «Сохранить», которая принимает эту модель представления и управляет созданием сущности ...
public ActionResult Save(CalendarEventViewModel viewModel)
{
if (!ModelState.IsValid)
return View(viewModel);
var calendarEntry = db.CalendarEntries.Include(x => x.Events)
.Single(x => x.CalendarEntryId = viewModel.CalendarEntryId);
var calendarEvent = new CalendarEvent
{
CalendarEntry = calendarEntry,
EventName = viewModel.EventName,
// .. etc.
};
calendarEntry.Events.Add(calendarEvent);
db.SaveChanges();
return RedirectToAction("Index");
}
Разница в том, что модели представления полностью независимы отсущности, которые их населяют.Они представляют данные, которые нужны представлению, и то, что контроллеру потребуется для определения местоположения соответствующих объектов, не более того.Вы можете использовать такие инструменты, как Automapper, чтобы эффективно копировать детали между объектами и просматривать модели.Обратите внимание, что в этом примере DbContext (db) не ссылается на DbSet для CalendarEvents?События являются дочерними для CalendarEntry, и контексту не нужен DbSet для каждой сущности, только те, которые нам нужны для непосредственного запроса.(сущности верхнего уровня) Я не хочу отдельных DbContexts для каждой сущности, потому что вы не можете использовать отношения между сущностями.В этом случае модель представления CalendarEvent будет иметь идентификатор CalendarEntry, который я могу использовать для нахождения записи.Затем я заполняю новую сущность для события из остальных деталей модели представления, затем добавляю эту новую запись в событие и вызываю SaveChanges.EF отслеживает изменения, внесенные в загруженный мной CalendarEntry, который распространяется на коллекцию событий.Мне не нужно отслеживать отдельный набор событий DbSet для добавления в контекст.
Другие вопросы, которые необходимо учитывать, это область действия DbContext (db).Вы хотите убедиться, что Контекст введен в ваш контроллер, а его срок действия ограничен сроком действия запроса.(Используя контейнер IoC, такой как Autofac, Unity и т. Д.), Вы хотите быть очень уверенными, что он не статичен и не работает дольше, чем запрос, потому что это приведет к проблемам с ресурсами / производительностью и потенциально к ошибкам / исключениям при одновременных запросах.
В худшем случае, если вы не уверены в том, как определяется область действия DbContext, или если он настроен как статический, вы должны изменить его использование на область действия внутри метода, а затем прочитать контейнеры Dependency Injection и IoC, чтобы охватить его дозапросить и внедрить его с помощью конструктора.
Например:
public ActionResult Save(CalendarEventViewModel viewModel)
{
if (!ModelState.IsValid)
return View(viewModel);
using( var db = new myDbContext())
{
var calendarEntry = db.CalendarEntries.Include(x => x.Events)
.Single(x => x.CalendarEntryId = viewModel.CalendarEntryId);
var calendarEvent = new CalendarEvent
{
CalendarEntry = calendarEntry,
EventName = viewModel.EventName,
// .. etc.
};
calendarEntry.Events.Add(calendarEvent);
db.SaveChanges();
}
return RedirectToAction("Index");
}