C# EntityFramework、Azure ElasticScale和每类型表(TPT)继承

C# EntityFramework、Azure ElasticScale和每类型表(TPT)继承,c#,entity-framework,azure-sql-database,azure-elastic-scale,C#,Entity Framework,Azure Sql Database,Azure Elastic Scale,如果给定一个在实体框架中使用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

如果给定一个在实体框架中使用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
}
既然Entity framework在派生类的表中不包含基类属性,我应该如何为拆分合并操作配置弹性伸缩模式信息?特别是租户ID,这是我的点地图切分键

SchemaInfo schemaInfo = new SchemaInfo();
schemaInfo.Add(new ShardedTableInfo("dbo", "ContactLinkCustomer", ???));
smm.GetSchemaInfoCollection().Add("ShardName", schemaInfo);
更新: ContactLink不是抽象的

更新2: 我应该注意,ContactLink也在我的DbContext中,并且是独立于ContactLinkCustomer进行查询的

更新3:
我没有使用TPH,我们实际上使用的是TPT。这就是导致多个表而不是带有鉴别器的单个表的原因。

如果您使用TPH,并且ContactLinkContactLinkCustomer都在同一层次结构中,则EF应该创建一个包含两个类中所有列的非规范化表。在这种情况下,ContactLink将是以租户ID作为分片键的分片表


但是,如果您确实计划使用多个表,则必须在ContactLinkCustomer的表中包含Tenant_ID列,并在租户ID上进行切分。当前版本的弹性缩放库和工具要求切分键出现在参与拆分合并的所有切分表中。

以下内容适用于我,需要注意的是,没有数据库级别的约束来保持租户ID的同步,因此,如果任何代码直接通过T-SQL(而不是EF)修改这些表,它们可能会失去同步

下面是我用于测试的其他类

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

也可能存在某种基于映射的解决方案。我试过下面的方法,但不起作用。也许通过更多的实验它可以工作,但是上面的解决方案对我来说已经足够好了,所以我没有进一步探讨它

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.
modelBuilder.Entity()
.Map(m=>
{
m、 属性(e=>e.Tenant\u ID);
m、 ToTable(“ContactLinkCustomer”);
});
未处理的异常:System.NotSupportedException:无法按照定义映射类型“ContactLinkCustomer”,因为它映射了从类型“”继承的属性
至少使用实体拆分或其他形式的继承。选择不同的继承映射策略以避免映射继承的属性,或者更改
层次结构中的所有类型映射继承的属性而不使用拆分。

好问题。我正在调查一些选择。在这种情况下,ContactLink是一个抽象类吗?(我在你发布的代码中看到它是具体的,只是想知道这是否是一种简化)。@jared moore该类不是抽象的。还有一个问题-如果你使用TPH,那么为什么会有ContactLinkCustomer表?我认为TPH应该为ContactLink和ContactLinkCustomer的层次结构生成一个表。太多的研究导致我混淆了主题。我想我们不是在使用TPH,而是在使用TPT。只有当基类是抽象的时,这才是正确的。在这种情况下,我们没有一个抽象类来生成两个表。通过ContactLink(联系人链接ID)的主键链接。我对将租户ID添加到派生类没有问题,但代码优先不会添加租户ID,而且我还没有找到强制添加租户ID的方法。我应该注意到,ContactLink也在我的DbContext中,并且是独立于ContactLinkCustomer进行查询的。快速更新:我们已经在此处发布了ShardManagement powershell模块以及一些示例脚本:。这将有助于您设置和查询现有的范围/列表映射。谢谢,我认为这会起作用。不幸的解决办法,但我认为没有其他办法。我要试试看
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.