Архитектура общих данных 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>();
}
}
Создана База Данных:
надеюсь, что это помогает.
Я собираюсь сделать предположение здесь, как я видел необычную ошибку в блоге Джули Лерманн сделал с ef4.1 Пространство имен в запросе вызвало проблему.
чтобы быстро проверить, является ли эта ошибка вашей проблемой, измените пространство имен всех объектов на одинаковое. Пространство имен xyz / / такое же, как dbcontext и и сущности public class OtherClass{}
быстрый тест. Если нет, извините, что отнял у вас время.