Архитектура общих данных Entity Framework multitenant: один столбец, несколько внешних ключей

у меня есть следующая структура данных:

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

Я получаю следующую ошибку:

компонент внешнего ключа "TenantId" не является объявленным свойством на введите 'SpecialOrder'. Убедитесь, что он не был исключен из модели и что это допустимое свойство примитива.

ошибка возникает при использовании конфигурации Fluent Api:

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

без OtherClass ссылка в SpecialOrder Я могу создавать объекты свободно без проблем (в том числе SpecialOrder, SuperSpecialOrder и т. д.).

кто-нибудь знает, что происходит? Я потерялся здесь: (

редактировать Я видел в других вопросах, что люди удаляют TenantId из таблиц, это не вариант, поскольку первичные ключи не уникальны для арендаторов, и мы хотим сохранить общую архитектуру данных.

Я знаю, что решением является наличие второго идентификатора в классе спецзаказу, но это не кажется мне логичным.

2 ответов


вы пытаетесь сделать TPT, где есть отдельная таблица для заказа / арендатора? Если это так, я думаю, что другой плакат правильный, и в EF есть ошибка.

Если клиенты / продукты являются вашими сопоставленными классами, это может сработать для вас.

что случилось со мной, когда я создал вашу базу данных, это попытка сопоставить класс абстрактного порядка.

добавил:

modelBuilder.Ignore<Order>();

строитель сохранил сопоставленные свойства из-за MapInheritedProperties, но не создавал таблицу, чтобы все FK были правильно созданы.

Я предполагаю, что вы хотели отдельные таблицы для каждого из ваших классов, как связанный пост выше, и не отображать абстрактную таблицу.

Все Модели:

 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>();


      }
   }

Создана База Данных: enter image description here

надеюсь, что это помогает.


Я собираюсь сделать предположение здесь, как я видел необычную ошибку в блоге Джули Лерманн сделал с ef4.1 Пространство имен в запросе вызвало проблему.

чтобы быстро проверить, является ли эта ошибка вашей проблемой, измените пространство имен всех объектов на одинаковое. Пространство имен xyz / / такое же, как dbcontext и и сущности public class OtherClass{}

быстрый тест. Если нет, извините, что отнял у вас время.