2012-08-14 5 views
8

Mam następującą strukturę danych:Entity Framework multitenant wspólna architektura dane: pojedyncza kolumna, wiele kluczy obcych

//property Notification 
abstract class BindableBase { } 
//base class for all tenant-scoped objects 
abstract class TenantModelBase : BindableBase 
{ 
    int TenantId; 
} 

abstract class Order : TenantModelBase 
{ 
    Customer Customer; //works: mapped using TenantId and CustomerId 
    Product Product; //again, works with TenantId and ProductId 
    string ProductId; 
    string CustomerId; 
} 
class Customer: TenantModelBase 
{ 
    string CustomerId; 
} 

class Product : TenantModelBase 
{ 
    string ProductId; 
} 

class SpecialOrder : Order 
{ 
    OtherClass OtherClass; //this fails!, see below 
    string OtherClassId; 
} 
class SuperSpecialOrder : SpecialOrder { } 

class OtherClass : TenantModelBase 
{ 
    string OtherClassId; 
} 

pojawia się następujący błąd:

The foreign key component 'TenantId' is not a declared property on type 'SpecialOrder'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

błąd występuje przy użyciu Fluent Configuration Api :

 config.HasRequired(p => p.OtherClass) 
      .WithMany(oc => oc.SpecialOrders) 
      .HasForeignKey(p => new { p.TenantId, p.OtherClassId}); 

Bez numeru referencyjnego OtherClass w SpecialOrder Mogę swobodnie tworzyć obiekty bez problemów (w tym SpecialOrder, SuperSpecialOrder itp.).

Ktoś ma pojęcie, co się dzieje? Gubię tutaj :(

Edycja widziałem w innych pytań, które ludzie usuwają TenantId z tabel, to nie jest opcją, ponieważ klucze podstawowe nie są unikalne w całej lokatorów i chcemy zachować wspólne architektura danych.

wiem obejście jest posiadanie drugiego TenantId w klasie SpecialOrder, ale to nie wydaje się logiczne, aby mnie.

+0

Myślę, że to ten sam problem, jak ten: http: // stackoverflow.com/questions/10961690/dziedziczenie-i-kompozytu-klucze-zagraniczne-jedna-część-klucza-w-klasie---podstawowej Czy możesz pokazać swoje mapowanie dokładniej? Co to jest 'config'? Przypuszczam, że 'EntityTypeConfiguration ' z 'T' =' SpecialOrder', prawda? Jak wygląda mapowanie dla 'Order.Customer'? Czy tworzysz to mapowanie za pomocą 'T' =' SpecialOrder' lub 'T' =' Order '? – Slauma

+0

Problem pojawia się, gdy określam mapowanie dla zamówienia i zamówienia specjalnego. Następnie traci widok jakiejkolwiek własności zadeklarowanej w klasie bazowej w SpecialOrder. Wydaje się, że to samo pytanie. – Bas

Odpowiedz

7

Czy starasz się zrobić TPT, gdzie istnieje oddzielna tabela na zamówienie/Jeśli tak, to myślę, że drugi plakat jest prawidłowy, a w EF wystąpił błąd.

Jeśli klienci/produkty są twoimi mapowanymi klasami, to może Ci się to udać.

Co mi się przydarzyło, gdy utworzyłem twoją bazę danych, to próbowałem mapować abstrakcyjną klasę Zamówienia.

Dodając:

modelBuilder.Ignore<Order>(); 

Budowniczy przechowywane odwzorowanych właściwości ze względu na MapInheritedProperties, ale nie utworzyć tabelę tak, że wszystkie FK zostały prawidłowo utworzone.

Zakładam, że chciałeś osobne tabele dla każdej z twoich klas, takie jak powiązany post powyżej, i nie zamapuj swojej tabeli abstrakcyjnej.

Cały Model:

public abstract class BindableBase { } 
    //base class for all tenant-scoped objects 
    public abstract class TenantModelBase : BindableBase 
    { 
     [Key] 
     public virtual int TenantId { get; set; } 
    } 

    public abstract class Order : TenantModelBase 
    { 
     public Customer Customer { get; set; } //works: mapped using TenantId and CustomerId 
     public Product Product { get; set; } //again, works with TenantId and ProductId 
     public string ProductId { get; set; } 
     public string CustomerId { get; set; } 
    } 
    public class Customer : TenantModelBase 
    { 
     [Key] 
     public string CustomerId { get; set; } 
    } 

    public class Product : TenantModelBase 
    { 
     [Key] 
     public string ProductId { get; set; } 
    } 

    public class SpecialOrder : Order 
    { 
     [Key] 
     public int SpecialOrderId { get; set; } 
     public OtherClass OtherClass { get; set; } //this fails!, see below 
     public string OtherClassId { get; set; } 
    } 
    public class SuperSpecialOrder : SpecialOrder { } 

    public class OtherClass : TenantModelBase 
    { 
     public string OtherClassId { get; set; } 
     public ICollection<SpecialOrder> SpecialOrders { get; set; } 
    } 



    public class Model : DbContext 
    { 
     public DbSet<Customer> Customers { get; set; } 
     public DbSet<Product> Products { get; set; } 
     public DbSet<SpecialOrder> SpecialOrders { get; set; } 
     public DbSet<SuperSpecialOrder> SuperSpecialOrders { get; set; } 

     public DbSet<OtherClass> OtherClasses { get; set; } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
     modelBuilder.Entity<OtherClass>() 
      .HasKey(k => new { k.TenantId, k.OtherClassId }); 

     modelBuilder.Entity<Customer>() 
      .HasKey(k => new { k.TenantId, k.CustomerId }); 

     modelBuilder.Entity<Product>() 
      .HasKey(k => new { k.TenantId, k.ProductId }); 


     modelBuilder.Entity<SpecialOrder>() 
      .Map(m => 
        { 
         m.MapInheritedProperties(); 
         m.ToTable("SpecialOrders"); 
        }); 

     modelBuilder.Entity<SpecialOrder>().HasKey(k => new { k.TenantId, k.SpecialOrderId }); 

     modelBuilder.Entity<SuperSpecialOrder>() 
      .Map(m => 
      { 
      m.MapInheritedProperties(); 
      m.ToTable("SuperSpecialOrders"); 
      }) 
      .HasKey(k => new { k.TenantId, k.SpecialOrderId }); 

     modelBuilder.Entity<SpecialOrder>() 
      .HasRequired(p => p.OtherClass) 
      .WithMany(o => o.SpecialOrders) 
      .HasForeignKey(p => new { p.TenantId, p.OtherClassId }); 

     modelBuilder.Entity<Order>() 
      .HasRequired(o => o.Customer) 
      .WithMany() 
      .HasForeignKey(k => new { k.TenantId, k.CustomerId }); 

     modelBuilder.Entity<Order>() 
      .HasRequired(o => o.Product) 
      .WithMany() 
      .HasForeignKey(k => new { k.TenantId, k.ProductId }); 

     modelBuilder.Ignore<Order>(); 


     } 
    } 

utworzonej bazy danych: enter image description here

Nadzieja to pomaga.

+0

+1: Interesująca analiza! Widzę, że nie odwzorowywanie klasy "Zamów" rozwiązuje konkretny problem w pytaniu, ale zastanawiam się, czy problem nie jest przesunięty tylko o jeden poziom w górę hierarchii dziedziczenia. Wyobraź sobie, że 'SuperSpecialOrder' ma teraz odniesienie do' OtherClass'. Ponieważ podstawowa klasa 'SpecialOrder' jest teraz mapowana, myślę, że złożone mapowanie FK w' SuperSpecialOrder' rzuciłoby teraz ten sam wyjątek. Poza tym, czy wymagane jest mapowanie TPC zamiast TPT, aby to działało? – Slauma

+0

To wydaje się być jedynym rozwiązaniem, musimy zrezygnować z mapowania TPH. Dziękuję za wspaniałą odpowiedź! – Bas

0

Zgaduję, że widziałem niezwykły błąd na blogu, który Julie Lermann zrobił z ef4.1 Przestrzeń nazw w zapytaniu spowodowała problem.

Aby szybko sprawdzić, czy ten błąd jest problemem, zmień przestrzeń nazw wszystkich obiektów, tak aby była taka sama. Przestrzeń nazw xyz // taka sama jak dbcontext i and public class OtherClass {}

Szybki test. Jeśli nie, przepraszam za zmarnowanie twojego czasu.

+0

Witaj soadyp, dziękuję za twoje wejście, ale wszystkie klasy są już w tej samej przestrzeni nazw! – Bas

Powiązane problemy