如何创建可导航到多个实体类型的导航属性?

时间:2013-03-23 20:35:45

标签: entity-framework-5

我的域类(简化版)中有以下内容

public enum JobType
{
    SalesOrder = 1,
    StockOrder = 2
}
public class SalesOrder : LoggedEntity
{
    public string Name { get; set; }  // and other fields


}
public class StockOrder : LoggedEntity
{
    public string Name { get; set; }  // and other fields


}

public class Job : LoggedEntity
{
  public int JobType { get; set; } // jobtype enum
  public virtual LoggedEntity LinkedEntity { get; set; }
}

我的背景如下;

public class Context : DbContext
{
 public DbSet<Job> Jobs { get; set; }
 public DbSet<StockOrder> StockOrders { get; set; }
 public DbSet<SalesOrder> SalesOrders { get; set; }
 }

当我运行迁移时,我得到描述的错误[here] [1]因此使用抽象实体似乎不起作用。

我的问题是,如何创建可以导航到多个实体类型的导航属性?

如果JobType = SalesOrder,那么我想导航到销售订单,如果JobType = StockOrder,那么我想导航到库存订单。

我想使用Table Perirarchy策略[见TPH] [2]

2 个答案:

答案 0 :(得分:1)

诀窍是让EF忘记LoggedEntity类。根据此示例重新构建您的实体:

public enum JobType
{
  SalesOrder = 1,
  StockOrder = 2
}

public abstract class LoggedEntity
{
  public int Id { get; set; }
  public string Name { get; set; }  // and other fields
}

public abstract class BaseOrder : LoggedEntity // New base class for orders!!
{ }

public class SalesOrder : BaseOrder
{ }

public class StockOrder : BaseOrder
{ }

public class Job : LoggedEntity
{
  public JobType JobType { get; set; } // jobtype enum
  public virtual BaseOrder Order { get; set; }
}

public class Tph2Context : DbContext
{
  public DbSet<Job> Jobs { get; set; }
  public DbSet<BaseOrder> Orders { get; set; }
}

您将看到迁移创建了两个表,Jobs和BaseOrders(要改进的名称)。 Job现在有一个属性Order,可以是SalesOrderStockOrder

您可以按

查询特定的订单类型
contex.Orders.OfType<StockOrder>()

你会注意到EF不知道LoggedEntity,因为

context.Set<LoggedEntity>()

将抛出异常

  

实体类型LoggedEntity不是当前上下文的模型的一部分。

答案 1 :(得分:0)

 how do I create a navigation property that can navigate 
 to more than one entity type?

你不能这样做。至少不是现在。导航属性是描述实体之间关系的方式。最多,它们代表某种sql关系。所以你不能动态改变或定义这种关系。你必须事先定义它。

现在为了做到这一点,你必须为你的单独条件定义单独的导航属性,即

public class Job : LoggedEntity
{
  public int JobTypeSales { get; set; } 
  public int JobTypeStock { get; set; }

  public virtual SalesOrder SalesOrder { get; set; }
  public virtual StockOrder StockOrder { get; set; }
}

然后通过流畅的API在modelbuilder中的配置中链接它们。

     HasRequired(s => s.SalesOrder)
                .WithMany()
                .HasForeignKey(s => s.JobTypeSales).WillCascadeOnDelete(true);

     HasRequired(s => s.StockOrder)
                .WithMany()
                .HasForeignKey(s => s.JobTypeStock).WillCascadeOnDelete(true);

as for your error "Sequence Contains No Elements"

当您指定的Linq查询使用.First().Single().ToList()并且查询未返回任何数据时,会出现此错误。

所以为了避免使用.FirstOrDefault()SingleOrDefault()

显然有适当的空检查。