实体框架从具有不同表关系主/外键场景的两个表中进行选择

时间:2013-10-08 10:53:38

标签: asp.net entity-framework tsql foreign-keys primary-key

我有两个样本表:

SCENARIO 1

表1 - 成分

ingredientId(PK, int, not null)
userId(FK, int, not null)
timestamp(datetime, not null)

表2 - 成分附加信息

ingredientAdditionalInformationId(PK, int, not null)
ingredientId(FK, int, not null)
isApproved(bit, not null)
unitsConverted(bit, not null)

代码背后的选择职能:

public IQueriable GetIngredientData(int ingredientId)
{
  using (var context = new MyEntities())
  {
      var result = context.Ingredient
            .Where(i => i.ingredientId == ingredientId)
            .Select(i => new
            {
                 i.ingredientId,
                 i.userId
                 i.IngredientAdditionalInformation.FirstOrDefault(iai => iai.ingredientId = i.ingredientId).isApproved
                 i.IngredientAdditionalInformation.FirstOrDefault(iai => iai.ingredientId = i.ingredientId).unitsConverted
             });

          return result.ToList().AsQueriable();
  }
}

或选择加入(我知道您可以使用方法语法加入,但我可以更快地使用查询方法编写连接)

public IQueriable GetIngredientData(int ingredientId)
{
  using (var context = new MyEntities())
  {
       var result = from i in context.Ingredient
            join iai in context.IngredientAdditionalInformation on i.ingredientId equals iai.ingredientId
            where i.ingredientId == 1
            select new
            {
                 i.ingredientId,
                 i.userId
                 iai.isApproved
                 iai.unitsConverted
            };         

        return result.ToList().AsQueriable();
  }
}

如果使用join或FirstOrDefault()更好/更快,或者我应该编写不同的数据库表,如下面的示例2所示:

情景2

表1 - 成分

ingredientId(PK, int, not null)
userId(FK, int, not null)
timestamp(datetime, not null)

表2 - 成分

ingredientId(PK, FK, int, not null) //WITHOUT PRIMARY (ingredientAdditionalInformationId) AUTO INCREMENT KEY)
isApproved(bit, not null)
unitsConverted(bit, not null)

因为我知道每种成分只有一个额外的信息......

代码中的SELECT SENTANCE

using (var context = new MyEntities())
{
    var result = context.Ingredient
      .Where(i => i.ingredientId = 1)
      .Select(i => new
      {
           i.ingredientId,
           i.userId
           i.IngredientAdditionalInformation.isApproved
           i.IngredientAdditionalInformation.unitsConverted
       });
} 

如果我知道每个成分只有一个条目并且这是正确的使用实体框架的方法?

2 个答案:

答案 0 :(得分:2)

如果您在两个表之间保持一对一的关系,那么您的第二个设计会更好,因为它还可以确保数据库中的参照完整性。

然后,您可以在实体框架模型中将该属性设置为单个导航属性,并按如下方式简化EF查询。如果您在模型中启用了延迟加载的导航属性,那么如果您是

,则可以在不使用包含的情况下离开
var result = from i in context.Ingredient.Include("IngredientAdditionalInformation") select i;

然后按如下方式访问属性:

i.IngredientAdditionalInformation.isApproved

但是,你真的需要一张额外的桌子吗?只有三个属性,我只需将它们组合成一个表,然后立即为您提供所有属性。

答案 1 :(得分:2)

情景2更好,因为您说这两个表之间存在一对一的关系 您应该探索的另一个选项是使用Table Per Type Inheritance。在这种情况下,您不需要使用Include或join来指定预先加载。

假设你的table1 = IngredientBase和table2 = Ingredients并且在你的上下文中你已经设置了

public IQueryable<Ingredient> Ingredients { 
    get { return IngredientBases.OfType<Ingredient>(); } }

那么你只需要

using (var context = new MyEntities())
{
    var result = context.Ingredients.Where(i => i.ingredientId = 1);
} 

SQL明智的,第二个选择的scenario1和scenario2将产生几乎相同的计划。但是性能方面,scenario2会更好,更不用说成为1-1关系表的正确设计。