Architettura di dati condivisa multi-tenant di Entity Framework: singola colonna, più chiavi esterne

Ho la seguente struttura di dati:

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

Ottengo il seguente errore:

Il componente chiave esterna ‘TenantId’ non è una proprietà dichiarata sul tipo ‘SpecialOrder’. Verificare che non sia stato esplicitamente escluso dal modello e che sia una proprietà primitiva valida.

Si è verificato un errore utilizzando la configurazione di Fluent Api:

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

Senza il riferimento OtherClass in OtherClass posso creare oggetti liberamente senza problemi (inclusi SpecialOrder , SuperSpecialOrder ecc.).

Qualcuno ha idea di cosa sta succedendo? Sono perso qui 🙁

Modifica Ho visto in altre domande che le persone rimuovono il TenantId dalle tabelle, questa non è un’opzione in quanto le chiavi primarie non sono uniche tra i titolari e vogliamo mantenere l’architettura dei dati condivisa.

So che la soluzione alternativa è avere un secondo TenantId nella class SpecialOrder, ma questo non mi sembra logico.

Stai provando a fare un TPT, dove c’è una tabella separata per l’ordine / inquilino? Se è così, penso che l’altro poster sia corretto, e c’è un bug in EF.

Se i clienti / prodotti sono le tue classi mappate, questo potrebbe funzionare per te.

Cosa mi è successo quando ho creato il tuo database è stato provato a mappare la class Ordine astratta.

Aggiungendo:

 modelBuilder.Ignore(); 

Il builder ha mantenuto le proprietà mappate dovute a MapInheritedProperties, ma non ha creato la tabella in modo che tutte le FK siano state create correttamente.

Suppongo che tu volessi tabelle separate per ciascuna delle tue classi come il post correlato sopra e per non mappare la tua tabella astratta.

Modello intero:

  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 SpecialOrders { get; set; } } public class Model : DbContext { public DbSet Customers { get; set; } public DbSet Products { get; set; } public DbSet SpecialOrders { get; set; } public DbSet SuperSpecialOrders { get; set; } public DbSet OtherClasses { get; set; } protected override void OnModelCreating( DbModelBuilder modelBuilder ) { modelBuilder.Entity() .HasKey( k => new { k.TenantId, k.OtherClassId } ); modelBuilder.Entity() .HasKey( k => new { k.TenantId, k.CustomerId } ); modelBuilder.Entity() .HasKey( k => new { k.TenantId, k.ProductId } ); modelBuilder.Entity() .Map( m => { m.MapInheritedProperties(); m.ToTable( "SpecialOrders" ); } ); modelBuilder.Entity().HasKey( k => new { k.TenantId, k.SpecialOrderId } ); modelBuilder.Entity() .Map( m => { m.MapInheritedProperties(); m.ToTable( "SuperSpecialOrders" ); } ) .HasKey( k => new { k.TenantId, k.SpecialOrderId } ); modelBuilder.Entity() .HasRequired( p => p.OtherClass ) .WithMany( o => o.SpecialOrders ) .HasForeignKey( p => new { p.TenantId, p.OtherClassId } ); modelBuilder.Entity() .HasRequired( o => o.Customer ) .WithMany() .HasForeignKey( k => new { k.TenantId, k.CustomerId } ); modelBuilder.Entity() .HasRequired( o => o.Product ) .WithMany() .HasForeignKey( k => new { k.TenantId, k.ProductId } ); modelBuilder.Ignore(); } } 

Database creato: inserisci la descrizione dell'immagine qui

Spero che questo ti aiuti.

Sto andando a indovinare qui come ho visto un bug insolito in un blog che Julie Lermann ha fatto con ef4.1 Lo spazio dei nomi nella query ha causato un problema.

Solo per testare rapidamente se questo bug è il tuo problema, cambia lo spazio dei nomi di tutti gli oggetti per essere lo stesso. Namespace xyz // uguale al dbcontext e alle quadro public class OtherClass {}

Test veloce. Se non lo è, mi dispiace per aver perso tempo.