如果在实体框架中使用TPH提供表结构。
class ContactLink {
Guid Contact_Link_ID { get; set;} //pk
Guid Tenant_ID { get; set;} //fk
Guid Contact_ID { get; set;} //fk
}
class ContactLinkCustomer : ContactLink {
Guid Contact_Link_ID { get; set;} //fk
Guid Customer_ID { get; set;} //fk
}
如何为拆分合并操作配置弹性比例模式信息,因为实体框架不包含派生类表中的基类属性?特别是Tenant_ID,这是我的点映射分片键。
SchemaInfo schemaInfo = new SchemaInfo();
schemaInfo.Add(new ShardedTableInfo("dbo", "ContactLinkCustomer", ???));
smm.GetSchemaInfoCollection().Add("ShardName", schemaInfo);
更新 ContactLink不是抽象的。
更新2: 我应该注意,ContactLink也在我的DbContext中,并且独立于ContactLinkCustomer进行查询。
更新3: 我没有使用TPH,我们实际上正在使用TPT。这是导致多个表而不是带有鉴别器的单个表的原因。
答案 0 :(得分:1)
如果您正在使用TPH并且 ContactLink 和 ContactLinkCustomer 位于同一层次结构中,那么EF应该创建一个包含两个类中所有列的非规范化表。在这种情况下,ContactLink将是分片表,Tenant_ID作为分片键。
但是,如果您真的打算使用多个表,则必须在表中包含 ContactLinkCustomer 的Tenant_ID列,并在Tenant_ID上对其进行分片。当前版本的Elastic Scale库和工具要求分片键出现在参与拆分合并的所有分片表中。
答案 1 :(得分:1)
以下对我有用,但需要注意的是,没有数据库级约束可以使Tenant_ID保持同步,因此如果任何代码直接通过T-SQL(而不是通过EF)修改这些表,它们可能会失去同步。
[Table("ContactLink")] // TPT inheritance
class ContactLink
{
public Guid Contact_Link_ID { get; set; } //pk
public Guid Tenant_ID { get; set; } //fk
public Guid Contact_ID { get; set; } //fk
}
[Table("ContactLinkCustomer")] // TPT inheritance
internal class ContactLinkCustomer : ContactLink
{
// Dummy property to trick EF into creating it as a column for sharding purposes
// Callers should just directly use the base Tenant_ID property
// It would be nice if we could set this to be public/protected, but then EF
// won't create it as a column. Maybe there is a workaround for this?
[Column("Tenant_ID")]
public Guid Tenant_ID_ContactLinkCustomer
{
get { return base.Tenant_ID; }
set { base.Tenant_ID = value; }
}
public Guid Contact_Link_ID { get; set; } //fk
public Guid Customer_ID { get; set; } //fk
}
我用于测试的其他课程如下。
class Program
{
static void Main(string[] args)
{
string connStr = "Server=(local);Database=EfShardingTpt;Integrated Security=true";
using (MyDbContext myDbContext = new MyDbContext(connStr))
{
// Drop and recreate database
Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());
}
// Create ContactLinkCustomer
using (MyDbContext myDbContext = new MyDbContext(connStr))
{
ContactLinkCustomer clc = new ContactLinkCustomer
{
Contact_ID = Guid.Empty,
Contact_Link_ID = Guid.Empty,
Customer_ID = Guid.Empty,
Tenant_ID = Guid.Parse("00000000-0000-0000-0000-100000000000")
};
myDbContext.ContactLinkCustomers.Add(clc);
myDbContext.SaveChanges();
}
WriteTenantIds(connStr);
// Update through subtype
using (MyDbContext myDbContext = new MyDbContext(connStr))
{
ContactLinkCustomer clc = myDbContext.ContactLinkCustomers.First();
clc.Tenant_ID = Guid.Parse("00000000-0000-0000-0000-200000000000");
myDbContext.SaveChanges();
}
WriteTenantIds(connStr);
// Update through supertype
using (MyDbContext myDbContext = new MyDbContext(connStr))
{
ContactLink cl = myDbContext.ContactLinks.First();
cl.Tenant_ID = Guid.Parse("00000000-0000-0000-0000-300000000000");
myDbContext.SaveChanges();
}
WriteTenantIds(connStr);
}
private static void WriteTenantIds(string connectionString)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT Tenant_ID FROM ContactLink";
Guid contactLinkTenantId = (Guid) cmd.ExecuteScalar();
cmd.CommandText = "SELECT Tenant_ID FROM ContactLinkCustomer";
Guid contactLinkCustomerTenantId = (Guid)cmd.ExecuteScalar();
Console.WriteLine("{0} {1}", contactLinkTenantId, contactLinkCustomerTenantId);
}
}
}
class MyDbContext : DbContext
{
public MyDbContext(string connectionString) : base(connectionString)
{
}
public virtual DbSet<ContactLink> ContactLinks { get; set; }
public virtual DbSet<ContactLinkCustomer> ContactLinkCustomers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ContactLink>()
.HasKey(e => e.Contact_Link_ID);
modelBuilder.Entity<ContactLinkCustomer>()
.HasKey(e => e.Contact_Link_ID);
}
}
控制台输出:
00000000-0000-0000-0000-100000000000 00000000-0000-0000-0000-100000000000
00000000-0000-0000-0000-200000000000 00000000-0000-0000-0000-200000000000
00000000-0000-0000-0000-300000000000 00000000-0000-0000-0000-300000000000
也可能存在某种基于映射的解决方案。我尝试了以下但它不起作用。也许通过一些更多的实验它可以工作,但上面的解决方案似乎对我来说足够好所以我没有进一步探索它。
modelBuilder.Entity<ContactLinkCustomer>()
.Map(m =>
{
m.Properties(e => e.Tenant_ID);
m.ToTable("ContactLinkCustomer");
});
Unhandled Exception: System.NotSupportedException: The type 'ContactLinkCustomer' cannot be mapped as defined because it maps inherited properties from types th
at use entity splitting or another form of inheritance. Either choose a different inheritance mapping strategy so as to not map inherited properties, or change
all types in the hierarchy to map inherited properties and to not use splitting.