6

Zajmuję się tworzeniem wtyczki z EF6, kod pierwszy.Entity Framework: Udostępnianie obiektów w różnych kontekstach DbContours

Mam jeden główny kontekst z podmiotem o nazwie User:

public class MainDataContext : DbContext 
{ 
    public MainDataContext(): base("MainDataContextCS") {} 
    public DbSet<User> Users { get; set; } 
} 

A potem inny kontekst PluginX, na innym projekcie, który odwołuje się do jednej bazy:

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; } 
} 

I to starannie tworzy, na tej samej bazie danych (ten sam ciąg połączenia), tabela PluginX.Bookings.

Problem polega na tym, że jednostka Booking zawiera odniesienie do User jednostki:

public class Booking 
{ 
    public int Id { get; set;} 
    public virtual User CreationUser { get; set;} 
    public BookingStatus Status { get; set; } 
} 

i kiedy uruchomiony Add-Migration dla kontekstu wtyczki EF będzie starał się stworzyć kolejny User podmiot zwany PluginX.User.

Jak można to rozwiązać? Czy istnieje sposób udostępniania wspólnego elementu w innym DbContext?

+0

dlaczego nie dziedziczymy PluginContext z MainContext. – hazimdikenli

Odpowiedz

5

Podczas pracy z wieloma kontekstami masz dwie opcje:

  1. traktować każdego kontekstu jakby były osobne aplikacje. Wyobraź sobie, że twój użytkownik jest zasobem zewnętrznym, który dostajesz z usługi internetowej. Nie będzie można dodać do tego klucza obcego. W tym przypadku możesz dodać tylko identyfikator użytkownika w tabelach, a kiedy potrzebujesz szczegółów użytkownika, wywołaj zewnętrzną usługę, aby uzyskać je lub masz lokalną lekką kopię użytkownika w kontekście rezerwacji, którą będziesz aktualizować co jakiś czas z kontekstu Użytkownicy.To podejście jest dobre, gdy pracujesz z dużym systemem i chcesz wyizolować części (przeczytaj o DDD i kontekstach ograniczonych).
  2. Część z twoich 2 kontekstów, stwórz trzeci kontekst z całym modelem (użytkownicy, rezerwacje itp.). Będziesz używał pełnego kontekstu do tworzenia migracji i utrzymania struktury DB, ale w aplikacji będziesz używał mniejszych kontekstów. To bardzo proste rozwiązanie. Łatwo jest utrzymać migracje w jednym kontekście i nadal pozwala na izolowanie operacji DB w mniejszych kontekstach, które nie mają dostępu do niepowiązanych podmiotów.
1

Dodając jednostkę rezerwacji, nie należy używać metody DbSet.Add(). Zamiast tego użyj metody DbSet.Attach() i ustaw właściwość DbContext.Entry(Entity).State dla rezerwacji na i upewnij się, że DbContext.Entry(Entity).State dla użytkownika pozostaje dla użytkownika pozostaje EntityState.Unchanged.

Tak na przykład zamiast robić to:

pluginDataContext.dbBooking.Add(myNewBooking); 

Wykonaj:

pluginDataContext.dbBooking.Attach(myNewBooking); 
pluginDataContext.Entry(myNewBooking).State = EntityState.Added; 

To dlatego, że metoda Add() oznacza wszystkie podmioty na wykresie obiektów jak EntityState.Added co spowoduje wkładki bez sprawdzania jeśli podmiot już istnieje w bazie danych. Metoda Attach() po prostu powoduje, że kontekst zaczyna śledzenie obiektu.

Dlatego prawie nigdy nie używam DbSet.Add().

2

To rozwiązanie może pomóc: Entity Framework 6 Code First Migrations with Multiple Data Contexts. Jednak w tym przypadku oba konteksty znajdują się w tym samym projekcie. Nie wiem, czy działa z kontekstami, które są w dwóch różnych projektach (myślę, że powinno to być, jeśli używasz tej samej klasy do mapowania użytkownika). Zgodnie z tym, co powiedział blog, musisz skomentować wygenerowany kod związany z tabelą Użytkownicy po uruchomieniu polecenia Add-Migration dla kontekstu PluginX.