Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linq 实体框架首先选择不带.ToList()的新POCO_Linq_Linq To Sql_Entity Framework_Linq To Entities - Fatal编程技术网

Linq 实体框架首先选择不带.ToList()的新POCO

Linq 实体框架首先选择不带.ToList()的新POCO,linq,linq-to-sql,entity-framework,linq-to-entities,Linq,Linq To Sql,Entity Framework,Linq To Entities,我正在创建一个带有服务层(WCF网站)和Silverlight 4客户端的应用程序。RIA服务不是一个选项,所以我们创建中间类来来回传递。为了回答这个问题,让我们假设我正在来回传递美味的食物对象 public class FoodData { public int Id { get; set; } public string Name { get; set; } public Tastyness TastyLevel { get; set; } } EF模型本质上是同一个类,一个包

我正在创建一个带有服务层(WCF网站)和Silverlight 4客户端的应用程序。RIA服务不是一个选项,所以我们创建中间类来来回传递。为了回答这个问题,让我们假设我正在来回传递美味的
食物
对象

public class FoodData
{
  public int Id { get; set; }
  public string Name { get; set; }
  public Tastyness TastyLevel { get; set; }
}
EF模型本质上是同一个类,一个包含三个基本字段的表(Tastyness是一个int,对应于我们的enum Tastyness)

我发现自己在进行实体框架查询时经常使用这种语句:

public List<FoodData> GetDeliciousFoods()
{
  var deliciousFoods = entities.Foods
                               .Where(f => f.Tastyness == (int)Tastyness.Delicious)
                               .ToList()  // Necessary? And if so, best performance with List, Array, other?
                               .Select(dFood => dFood.ToFoodData())
                               .ToList();

  return deliciousFoods;
}
公共列表GetDeliciousFoods()
{
var deliciousFoods=实体。食品
.Where(f=>f.Tastyness==(int)Tastyness.Delicious)
.ToList()//是否需要?如果需要,列表、数组和其他的最佳性能?
.Select(dFood=>dFood.ToFoodData())
.ToList();
返回美味的食物;
}
如果没有.ToList()调用,我会遇到一个异常,即LINQ无法将自定义方法转换为查询等价物,我理解这一点

我的问题是在之前调用.ToList()。使用自定义扩展名选择(…),将对象转换为食物对象的POCO版本

这里是否有更好的模式,或者甚至是.ToList()的更好替代方案,因为我并不真正需要列表结果的功能,因此它的性能可能更高

使用
AsEnumerable()
将查询转换为常规的旧LINQ to Objects查询,而无需创建不需要的列表

var deliciousFoods = entities.Foods
                               .Where(f => f.Tastyness == (int)Tastyness.Delicious)
                               .AsEnumerable()
                               .Select(dFood => dFood.ToFoodData())
                               .ToList();
编辑:请参见第一个。ToList()不是必需的

var deliciousFoods = entities.Food

    // Here a lazy-evaluated collection is created (ie, the actual database query
    // has not been run yet)
    .Where(f => f.Tastyness == (int)Tastyness.Delicious)

    // With ToArray, the query is executed and results returned and 
    // instances of Food created.  The database connection
    // can safely be closed at this point.
    // Given the rest of the linq query, this step can be skipped
    // with no performance penalty that I can think of
    .ToArray()

    // Project result set onto new collection.  DB Query executed if
    // not already
    // The above .ToArray() should make no difference here other
    // than an extra function call an iteration over the result set
    .Select(dFood => dFood.ToFoodData())

    // This one might not be needed, see below
    .ToList();
您是否要求结果集是一个列表?或者仅仅一个IEnumerable或ICollection就足够了?如果是,则可能不需要最后一个.ToList()


你问过表演吗?您希望每个查询返回多少个实例?如果相对较少,那么.ToList()或.ToArray()或其他类型的文件不会产生任何有意义的差异。更多的是关于你需要公开什么样的功能?如果返回的对象需要是可索引的、可添加的,并且具有List的其他属性,那就可以了。但是,如果您所做的只是对返回的集合进行迭代,则不要公开不需要的内容。

使用
ToList
AsEnumerable
的问题在于,您具体化了整个实体并支付了修复成本。如果您希望获得只返回所需字段的最佳SQL,则应直接投影,而不是使用
.ToFoodData()

强制转换到枚举可能有问题。如果是,请使用匿名类型:

var deliciousFoods = entities.Foods
                             .Where(f => f.Tastyness == (int)Tastyness.Delicious)
                             .Select(dFood => new FoodData
                                  {
                                      Id = dFood.Id,
                                      Name = dFood.Name,
                                      TastyLevel = dFood.Tastyness
                                  })
                             .AsEnumerable()
                             .Select(dFood => new FoodData
                                  {
                                      Id = dFood.Id,
                                      Name = dFood.Name,
                                      TastyLevel = (Tastyness)dFood.TastyLevel
                                  });

如果您检查生成的SQL,您会发现它更简单,并且您不需要支付将对象固定到ObjectContext中的费用。

Craig Stuntz的答案是正确的,但是当您有多个查询需要将“Food”对象转换为“FoodData”对象时,可能会出现问题。您不希望表达式在多个位置重复(干燥)

解决方案可以是不使用实际返回“FoodData”对象的方法,而是使用返回用于进行转换的表达式的方法。然后可以重新使用此方法

Class Food {
  ...

  public static Expression<Func<Food, FoodData> ConvertToFoodDataExpr() {
    Expression<Func<Food, FoodData>> expr = dFood => new FoodData 
    {
      Id = dFood.Id,
      Name = dFood.Name,
      TastyLevel = dFood.Tastyness
    }
  }
}

请记住,在使用实体框架时,在应用select表达式之前,不应具体化IEnumerable(使用ToList、ToArray等),否则,Entity Framework将无法生成正确的select语句,它将始终从表中选择所有字段。

internet上的陌生人先生,您是否有任何数据支持它具有更好的性能?;)看起来很直截了当。我仍然想尝试对大型数据集进行一些实验,看看时间上的差异。我看不到任何性能问题。我要说的一件事是,使用可计算vs ToList时,光标将保持更长的打开时间。假设dFood.ToFoodData没有做任何重要的事情,这个问题几乎没有意义。但是为了解释一下,如果每次调用都需要10秒,那么AsEnumerable在返回每个记录和从数据库一次发送所有记录之间需要10秒。当我尝试使用AsEnumerable时,我注意到我遇到了一些间歇性的“底层连接关闭”类型的异常。我想我更喜欢下面的投影,看起来更干净。是的。你的第一个例子,直接投影,确实非常好吃。非常好,这正是我想要得到更好解释的。在我的例子中,我使用数据传输对象(FoodData)中对象的所有字段,因此SQL可能没有太多改进。从现在起,这些信息将影响我查询实体集合的方式。使用AsEnumerable()ToArray的+1比ToList成本更高,因为实现首先填充列表,然后从列表中创建数组。
Class Food {
  ...

  public static Expression<Func<Food, FoodData> ConvertToFoodDataExpr() {
    Expression<Func<Food, FoodData>> expr = dFood => new FoodData 
    {
      Id = dFood.Id,
      Name = dFood.Name,
      TastyLevel = dFood.Tastyness
    }
  }
}
var deliciousFoods = entities.Foods
                         .Where(f => f.Tastyness == (int)Tastyness.Delicious)
                         .Select(Food.ConvertToFoodDataExpr());