2

我花了周末的大部分时间试图弄清楚这一点。

我有一个带有订阅表的现有数据库,我想使用 TPH 继承策略将其映射到我的域中的实体。

Subscription 有几种类型,每种都有自己的特点,因此需要继承。这是域的简化版本:

public class Subscription
{
    public int CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
    public int SubscriptionID { get; set; }
    public string Name { get; set; }
}
public class BookSubscription:Subscription
{
    public string Book { get; set; }
}
public class TVSubscription : Subscription
{
    public string Channel { get; set; }
}

这些实体在上下文中映射如下:

public DbSet<Customer> Customers { get; set; }
public DbSet<Subscription> Subscriptions { get; set; }
public DbSet<TVSubscription> TVSubscriptions { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Customer>().ToTable("tblCustomer");
    modelBuilder.Entity<Customer>().HasKey(t => t.CustomerID);

    modelBuilder.Entity<Subscription>()
            .Map<Subscription>(m =>
            {
                m.ToTable("tblSubscription");
                m.Requires("ServiceTypeId").HasValue(1);
            })
             .Map<TVSubscription>(m =>
             {
                 m.Requires("ServiceTypeId").HasValue(20);
             })
            .Map<BookSubscription>(m =>
            {
                m.Requires("ServiceTypeId").HasValue(5);
            }
            );
    modelBuilder.Entity<Subscription>().HasKey(s => s.SubscriptionID);

    base.OnModelCreating(modelBuilder);
}

正如预期的那样,当查询任何派生类的上下文时,EF 使用 ServiceTypeId 作为鉴别器正确构造查询。当我尝试在 Customer 实体中包含派生类时,就会出现问题。这有效:

public class Customer
{
    public int CustomerID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Subscription> Subscriptions{ get; set; }      
}

这不起作用:

public class Customer
{
    public int CustomerID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Subscription> Subscriptions{ get; set; }
    public virtual ICollection<TVSubscription> TvSubscriptions { get; set; }
}

这也不是:

public class Customer
{
    public int CustomerID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<TVSubscription> TvSubscriptions { get; set; }
}

当我检查分析器时,我可以看到在这两种情况下,EF 添加了 _id 后缀并尝试查询除 customerID 之外的不存在的 customer_id 列。我试图为派生类型显式映射外键,但 EF 然后抱怨:

外键组件“CustomerID”不是“TVSubscription”类型的声明属性。验证它没有被明确地从模型中排除,并且它是一个有效的原始属性。

CustomerID 在派生类中没有位置,但即使我尝试将它移到那里它也不起作用(我怀疑是因为 EF 正在尝试使用另一种继承策略进行映射)。

现在,我知道我可以这样做:

public IEnumerable<TVSubscription> TvSubscriptions
{
    get { return Subscriptions.OfType<TVSubscription>(); }
}

但是,使用这种方法,EF 会在 db 中查询整个订阅集,然后在本地对其进行过滤以仅返回 TVSubscriptions。这当然不是理想的,因为客户可以有数百个订阅,最好我希望 EF 只查询并返回某种类型的订阅——就像我在使用 dbContext 时所做的那样。

所以问题是,如何在 Customer 类中包含 TVSubscriptions 列表并让 EF 仅查询这些?

如果这是不可能的,当我将派生类的集合添加到客户实体时,有人可以解释 EF 做出什么样的假设。

4

0 回答 0