Linq 使用 Join 表进行 Group by / Distinct
Linq Group by / Distinct with Join table问题的出现原因以及解决方法
在使用Linq进行数据查询时,有时候需要对结果进行分组或去重操作。然而,在涉及到多个表的连接查询时,由于表之间的关联关系,可能会导致分组或去重操作无法正常进行,从而出现问题。
下面的代码段展示了一个例子,其中使用了Linq的Group by和Join操作来对数据库中的两个表进行连接查询,并根据语言字段对结果进行分组:
var query = from r in db.SURV_Question_Ext_Model join s in db.SURV_Question_Model on r.Qext_Question_ID equals s.Question_ID where s.Question_Survey_ID == Survey_ID group new {r, s} by r.language into rg select rg.Key;
在这段代码中,db是一个数据库上下文对象,SURV_Question_Ext_Model和SURV_Question_Model是两个表的模型。通过Join操作,将这两个表连接起来,并根据条件筛选出符合要求的数据。然后,通过Group by操作,将结果按照语言字段进行分组,并将分组后的结果保存在rg对象中。最后,通过select操作,将分组的键值rg.Key返回。
然而,有时候在执行这段代码时,可能会遇到报错或者结果不符合预期的情况。这是因为在进行分组或去重操作时,Linq的默认行为是对整个对象进行比较,而不仅仅是对指定的字段进行比较。在上述代码中,由于rg对象是一个匿名类型的集合,Linq无法确定如何对其进行比较,导致出现问题。
为了解决这个问题,可以采用以下方法之一:
1. 使用Distinct方法进行去重操作:将Group by操作改为Distinct操作,只保留不重复的语言字段值。
var query = (from r in db.SURV_Question_Ext_Model join s in db.SURV_Question_Model on r.Qext_Question_ID equals s.Question_ID where s.Question_Survey_ID == Survey_ID select r.language).Distinct();
2. 自定义比较器进行分组操作:创建一个自定义的比较器,实现IEqualityComparer接口,并在Group by操作中使用该比较器来比较语言字段。
public class LanguageComparer : IEqualityComparer{ public bool Equals(SURV_Question_Ext_Model x, SURV_Question_Ext_Model y) { return x.language == y.language; } public int GetHashCode(SURV_Question_Ext_Model obj) { return obj.language.GetHashCode(); } } var query = from r in db.SURV_Question_Ext_Model join s in db.SURV_Question_Model on r.Qext_Question_ID equals s.Question_ID where s.Question_Survey_ID == Survey_ID group r by r into rg select rg.Key;
通过使用Distinct方法或自定义比较器,可以解决在Linq Group by / Distinct with Join table中出现的问题,并得到符合预期的结果。通过对Linq的操作进行合理调整,可以更好地实现数据查询和处理的需求。
在这段内容中,提到了使用Linq的Group by和Distinct方法与Join表格的问题。问题的原因是,虽然MoreLinq中的DistinctBy方法可以对IEnumerable进行操作,但无法在EF查询中使用。然而,可以使用相同的方法解决这个问题。解决方法是使用Join将两个表格连接起来,并根据特定的条件进行分组,然后选择每个分组的第一个元素作为结果。
在这个例子中,首先使用Join将SURV_Question_Ext_Model和SURV_Question_Model表格连接起来,然后根据条件s.Question_Survey_ID == Survey_ID进行过滤。接下来,使用Group by将结果按照r.language进行分组,并选择每个分组的第一个元素作为结果。这样做的原因是,可能数据库返回的语言顺序不同,所以通过分组和选择第一个元素可以确保结果的唯一性。
然而,作者对这个方法的结果是否符合需求表示了疑问。作者建议添加一个特定语言的断言,并移除分组操作。这样做的目的是为了确保结果只包含特定语言的数据,并且不依赖数据库返回的语言顺序。修改后的代码如下:
var query = from r in db.SURV_Question_Ext_Model
join s in db.SURV_Question_Model
on r.Qext_Question_ID equals s.Question_ID
where s.Question_Survey_ID == Survey_ID
&& r.language == someVariable
select new { r, s };
此外,如果SURV_Question_Ext_Model和SURV_Question_Model之间存在导航属性的关联,可能会改进一些问题。