我有一个泛型类,应该通过调用此方法来过滤,排序,投影和分页IQueryable
:
public async Task<PagedResult<TResult>> GetFilteredOrderedPageAsync<TResult>(IQueryable<TSource> source,
IFilterModel filterModel,
ISortModel sortModel,
int page, int pageSize,
Expression<Func<TSource, TResult>> converter)
where TResult : class
{
var filtered = Filter(source, filterModel);
var projected = filtered
.Select(converter)
.Distinct();
var ordered = Sort<TResult>(projected, sortModel);
var result = await GetPageAsync<TResult>(ordered, page, pageSize, converter);
return result;
}
我在这里打电话给Distinct()
var projected = filtered
.Select(converter)
.Distinct();
删除投影后可能出现的任何重复项。
我的假设是EF6会产生类似
的东西SELECT DISTINCT Col1, Col2, Col3 FROM (SELECT Col1, Col2, Col3, Col4 FROM SOME_TABLE WHERE <some conditions on co1, col2, col3, col4 ...>)
即。它会将DISTINCT
应用于投影,因此,如果有两行具有相同的col1,col2,col3但不同的col4,则只有一行会使其成为结果。
但是,我得到的SQL看起来像这样:
SELECT Col1, Col2, Col3, Col4 FROM (SELECT DISTINCT Col1, Col2, Col3, Col4 FROM SOME_TABLE)
- 没有投影,DISTINCT被转移到子查询中,好像我这样做:
var projected = filtered
.Distinct()
.Select(converter)
我希望这项服务是通用的,即可能与任何TSource
和TResult
一起使用,但看起来这里存在一些陷阱,而我对EF所做的事情的理解是不正确的。
这里发生了什么?
更新
我认为问题出在我的转换器上。我使用以下函数生成传递给Select
的lambda表达式:
public class ProvidersViewModel
{
public string Name { get; set; }
public Rate Rate { get; set; }
publi QA QA { get; set; }
...
public static Expression<Func<ProviderJoinRateAndQA, ProvidersViewModel>> FromProvider(bool showRateAndQA)
{
return x => new ProvidersViewModel {
Name = x.Name,
Rate = showRateAndQA ? new Rate { Amount = x.Rate.Amount ... } : null,
Rate = showRateAndQA ? new QA { Grade = x.QA.Grade ... } : null
};
}
}
ProviderJoinRateAndQA
是提供商,他们的费率和QAs的连接。每个Provider
可以有多个服务,费率和qas。在某些情况下,我希望视图模型隐藏速率和QA信息。我假设我可以通过将null
分配给Rate
和QA
属性来实现,但它似乎不起作用:Distinct
工作不正常。
我换了之后
Rate = showRateAndQA?新QA {Grade = x.QA.Grade ...}:null
同
Rate = new QA {Grade = showRateAndQA? x.QA.Grade:null ...},
Distinct
工作正常。
显然EF不喜欢我在我的lambda中指定null
对象。
答案 0 :(得分:0)
从内存中,默认的Distinct()
实现使用相应类的默认Equals()
方法,这通常是不需要的(我发现这是我的工作至少的情况) )。
您需要设置如下内容;
public class ProvidersViewModel : IEqualityComparer<ProvidersViewModel>
{
public bool Equals(ProvidersViewModel x, ProvidersViewModel y)
{
if (x.col1 == y.col1 && x.col2 == y.col2 && x.col3 == y.col3)
return true;
else
return false;
}
public int GetHashCode(ProvidersViewModel obj)
{
int hCode = obj.col1 ^ obj.col2 ^ obj.col3;
return hCode.GetHashCode();
}
// Existing code, fields, etc.
}
然后,这应允许Distinct()
的呼叫正常工作。