我有以下数据结构:
//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,这不是一个选项,因为主键在租户中不是唯一的,我们希望保留共享数据架构。
我知道解决方法是在SpecialOrder类中有第二个TenantId,但这对我来说似乎不合逻辑。
答案 0 :(得分:7)
您是否正在尝试进行TPT,其中有一个单独的订单/租户表?如果是这样,我认为另一张海报是正确的,EF中有一个错误。
如果客户/产品是基于您的映射类,这可能对您有用。
我在创建数据库时发生了什么事情,它试图映射抽象的Order类。
添加:
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>();
}
}
创建的数据库:
希望这有帮助。
答案 1 :(得分:0)
我想在这里猜一下,因为我看到Julie Lermann在ef4.1博客中发现的一个不寻常的错误 查询中的命名空间导致了一个问题。
只是为了快速测试这个bug是否是您的问题,将所有对象的命名空间更改为相同。 命名空间xyz //与dbcontext和实体相同 公共类OtherClass {}
快速测试。如果不是,抱歉浪费你的时间。