C# Linq 按对象分组
C# Linq Group by Object
我在 LINQ to SQL 语句中使用 group by 时遇到问题。
我的鳕鱼是
var combinedItems = (from article in articles
join author in authors
on article.AuthorId equals author.Id into tempAuthors
from tempAuthor in tempAuthors.DefaultIfEmpty()
select new { article , author = tempAuthor});
var groups1 = (from combinedItem in combinedItems
group combinedItem by combinedItem.article into g
select g.Key).ToList();
var groups2 = (from combinedItem in combinedItems
group combinedItem by combinedItem.article.Id into g
select g.Key).ToList();
我尝试用两种不同的方式进行分组。第一种方式,我按对象分组,第二种方式我只按其中一个对象中的字段分组。
当我 运行 groups1
时,我收到一条错误消息,提示需要在客户端进行评估,而当我使用 groups2
时,一切正常。请问有什么问题吗?如果我想按对象分组,有什么办法吗?
如果您想按对象分组,因为您没有在 Article
class 中覆盖 Equals
和 GetHashCode()
或实现 IEqualityComparer<Article>
您只是获得默认比较,它检查引用是否相等。所以你需要的是这样的:
class GroupItemComparer : IEqualityComparer<Article>
{
public bool Equals(Article x, Article y)
{
return x.Id == y.Id &&
x.Name == y.Name;
}
public int GetHashCode(Article obj)
{
return obj.Id.GetHashCode() ^
obj.Name.GetHashCode();
}
}
然后您需要将查询更改为 lambda 表达式:
var groups1 = combinedItems.GroupBy(c => c.article , new GroupItemComparer())
.Select(c => c.Key).ToList();
如果您在将方法转换为 SQL 时遇到任何异常,您可以在 GroupBy
方法之前使用 AsEnumerable
或 ToList
方法,在之后使用此方法加载数据后,将使用 Linq to Objects 对内存中已有的数据执行任何进一步的操作。
正如其他人指出的那样,GroupBy
默认使用 引用相等性 ,您可以通过指定一个或多个 来绕过它properties 作为分组依据。但是为什么会出错?
查询的重点是将您的 Linq 查询转换为 SQL。由于客户端上的对象引用相等性不能轻易翻译成 SQL,翻译器不支持它并给你一个错误。
当您提供一个或多个属性作为分组依据时,提供商可以将其转换为SQL(例如GROUP BY article.Id
), 因此第二种方法没有错误。
我在 LINQ to SQL 语句中使用 group by 时遇到问题。
我的鳕鱼是
var combinedItems = (from article in articles
join author in authors
on article.AuthorId equals author.Id into tempAuthors
from tempAuthor in tempAuthors.DefaultIfEmpty()
select new { article , author = tempAuthor});
var groups1 = (from combinedItem in combinedItems
group combinedItem by combinedItem.article into g
select g.Key).ToList();
var groups2 = (from combinedItem in combinedItems
group combinedItem by combinedItem.article.Id into g
select g.Key).ToList();
我尝试用两种不同的方式进行分组。第一种方式,我按对象分组,第二种方式我只按其中一个对象中的字段分组。
当我 运行 groups1
时,我收到一条错误消息,提示需要在客户端进行评估,而当我使用 groups2
时,一切正常。请问有什么问题吗?如果我想按对象分组,有什么办法吗?
如果您想按对象分组,因为您没有在 Article
class 中覆盖 Equals
和 GetHashCode()
或实现 IEqualityComparer<Article>
您只是获得默认比较,它检查引用是否相等。所以你需要的是这样的:
class GroupItemComparer : IEqualityComparer<Article>
{
public bool Equals(Article x, Article y)
{
return x.Id == y.Id &&
x.Name == y.Name;
}
public int GetHashCode(Article obj)
{
return obj.Id.GetHashCode() ^
obj.Name.GetHashCode();
}
}
然后您需要将查询更改为 lambda 表达式:
var groups1 = combinedItems.GroupBy(c => c.article , new GroupItemComparer())
.Select(c => c.Key).ToList();
如果您在将方法转换为 SQL 时遇到任何异常,您可以在 GroupBy
方法之前使用 AsEnumerable
或 ToList
方法,在之后使用此方法加载数据后,将使用 Linq to Objects 对内存中已有的数据执行任何进一步的操作。
正如其他人指出的那样,GroupBy
默认使用 引用相等性 ,您可以通过指定一个或多个 来绕过它properties 作为分组依据。但是为什么会出错?
查询的重点是将您的 Linq 查询转换为 SQL。由于客户端上的对象引用相等性不能轻易翻译成 SQL,翻译器不支持它并给你一个错误。
当您提供一个或多个属性作为分组依据时,提供商可以将其转换为SQL(例如GROUP BY article.Id
), 因此第二种方法没有错误。