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 ответов


при работе с несколькими контекстами у вас есть два варианта:

  1. относитесь к каждому контексту, как к отдельным приложениям. Представьте, что ваш пользователь-это внешний ресурс, который вы получаете от веб-сервиса. Вы не сможете добавить внешний ключ к этому. В этом случае вы либо добавляете только идентификатор пользователя в свои таблицы, а когда вам нужны данные пользователя, вызываете внешнюю службу, чтобы получить их, либо имеете локальную светлую копию пользователя в контексте бронирования, который вы бы обновляйте время от времени из контекста Users. Этот подход хорош, когда вы работаете с большой системой, и вы хотите изолировать части (читайте о DDD и ограниченных контекстах)
  2. часть из ваших 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().