Linq 实体框架首先选择不带.ToList()的新POCO
我正在创建一个带有服务层(WCF网站)和Silverlight 4客户端的应用程序。RIA服务不是一个选项,所以我们创建中间类来来回传递。为了回答这个问题,让我们假设我正在来回传递美味的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模型本质上是同一个类,一个包
食物
对象
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());