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?


comment
защо не наследявате PluginContext от MainContext.   -  person hazimdikenli    schedule 16.01.2015


Отговори (4)


Когато работите с множество контексти, имате две възможности:

  1. Отнасяйте се към всеки контекст като към отделни приложения. Представете си, че вашият потребител е външен ресурс, който получавате от уеб услуга. Няма да можете да добавите външен ключ към това. Това, което бихте направили в това, е или да добавите само userId във вашите таблици и когато имате нужда от потребителските данни, да се обадите на външната услуга, за да ги получите, или да имате локално леко копие на потребителя в контекста на резервациите, което бихте актуализирали от време на време от контекста на потребителите. Този подход е добър, когато работите с голяма система и искате да изолирате частите (прочетете за DDD и ограничените контексти)
  2. Освен вашите 2 контекста, създайте трети контекст с целия модел (потребители, резервации и т.н.). Ще използвате пълния контекст, за да създадете миграциите и да поддържате структурата на DB, но в приложението ще използвате по-малките контексти. Това е много просто решение. Лесно е да се поддържат миграциите с един контекст и все пак ви позволява да изолирате операцията в DB в по-малки контексти, които нямат достъп до несвързани обекти.
person Francesc Castells    schedule 27.11.2015
comment
Това също ми помогна да помисля за моя модел и да се опитам да денормализирам определени части от моето приложение. - person Steven Ryssaert; 07.04.2019
comment
Хей Franscesc, има ли промени в този подход? Все още ли не е възможно с EF Core 3.0 да се свързват обекти в различни контексти? - person liqSTAR; 06.10.2020

Когато добавяте обект Резервация, не използвайте метода 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, което ще доведе до вмъквания, без да се проверява дали обектът вече съществува в базата данни. Методът Attach() просто кара контекста да започне да проследява обекта.

Ето защо почти никога не използвам DbSet.Add().

person JC Ford    schedule 15.01.2015

Можете да опитате да използвате изгледи, да декларирате потребителя като изглед в PluginDataContext и когато извършите миграцията, въведете метода „създайте потребителски изглед като ...“, това ви позволява да свържете книгата с потребителя.

person Juan Jimenez Cervantes Frigols    schedule 09.03.2020

Това решение може да ви помогне:Първи миграции на код на Entity Framework 6 с множество контексти на данни. В този случай обаче и двата контекста са в един и същ проект. Не знам дали работи с контексти, които са в два различни проекта (мисля, че трябва, ако използвате един и същ клас за картографиране на потребител). Както се казва в блога, трябва да коментирате генерирания код, свързан с таблицата Users, когато изпълнявате командата Add-Migration за контекста на PluginX.

person octavioccl    schedule 15.01.2015
comment
Знам, че това е старо, но... Не можех да спра да мисля, че това решение изобщо не е страхотно. Всеки път, когато се добавя нова миграция, трябва да коментирате код? Звучи ми като огромен хак. - person jpgrassi; 27.06.2019