Entity Framework: совместное использование сущностей в разных DbContexts
Я разрабатываю приложение плагина с EF6, сначала код.
у меня есть один основной контекст с сущностью под названием User
:
public class MainDataContext : DbContext
{
public MainDataContext(): base("MainDataContextCS") {}
public DbSet<User> Users { get; set; }
}
а затем другой контекст для PluginX, в другом проекте, который ссылается на базовый:
public class PluginDataContext : DbContext
{
public PluginDataContext () : base("MainDataContextCS") {
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.HasDefaultSchema("PluginX");
base.OnModelCreating(modelBuilder);
}
public DbSet<Booking> Bookings { get; set; }
}
и это аккуратно создает в той же базе данных (та же строка подключения)PluginX.Bookings
таблица.
проблема здесь в том, что Booking
объект содержит ссылку на User
сущность:
public class Booking
{
public int Id { get; set;}
public virtual User CreationUser { get; set;}
public BookingStatus Status { get; set; }
}
и Add-Migration
для контекста плагина EF попытается создать другой User
сущности PluginX.User
.
как это можно решить? Есть ли способ поделиться общей сущностью, в другом DbContext
?
3 ответов
при работе с несколькими контекстами у вас есть два варианта:
- относитесь к каждому контексту, как к отдельным приложениям. Представьте, что ваш пользователь-это внешний ресурс, который вы получаете от веб-сервиса. Вы не сможете добавить внешний ключ к этому. В этом случае вы либо добавляете только идентификатор пользователя в свои таблицы, а когда вам нужны данные пользователя, вызываете внешнюю службу, чтобы получить их, либо имеете локальную светлую копию пользователя в контексте бронирования, который вы бы обновляйте время от времени из контекста Users. Этот подход хорош, когда вы работаете с большой системой, и вы хотите изолировать части (читайте о DDD и ограниченных контекстах)
- часть из ваших 2 контекстов, создайте третий контекст со всей моделью (пользователи, заказы и т. д.). Вы будете использовать полный контекст для создания миграций и поддержания структуры БД, но в приложении вы будете использовать меньшие контексты. Это очень простое решение. Легко поддерживать миграции с одним контекстом, и это все еще позволяет изолировать операцию БД в меньших контекстах, которые не имеют доступа к несвязанным сущностям.
Это решение может помочь вам:Entity Framework 6 Первые миграции кода с несколькими контекстами данных. Однако в этом случае оба контекста находятся в одном проекте. Я не знаю, работает ли с контекстами, которые находятся в двух разных проектах (я думаю, это должно быть, если вы используете один и тот же класс для отображения пользователя). Как сказано в блоге, вам нужно прокомментировать сгенерированный код, связанный с таблицей Users при запуске Add-Migration
команда для контекста PluginX.
при добавлении объекта бронирования не используйте DbSet.Add()
метод. Вместо этого используйте DbSet.Attach()
метод DbContext.Entry(Entity).State
недвижимость для бронирования в EntityState.Added
и обязательно DbContext.Entry(Entity).State
для пользователя остается EntityState.Unchanged
.
так, например, вместо этого:
pluginDataContext.dbBooking.Add(myNewBooking);
этого:
pluginDataContext.dbBooking.Attach(myNewBooking);
pluginDataContext.Entry(myNewBooking).State = EntityState.Added;
это так Add()
метод помечает все объекты в графе объектов, как EntityState.Added
что вызовет вставки без проверки того, существует ли объект уже в базе данных. The Attach()
метод просто заставляет контекст начать отслеживать сущность.
вот почему я почти никогда не использую DbSet.Add()
.