简体   繁体   English

IQueryable 上的 EF Distinct 不会删除重复项

[英]EF Distinct on IQueryable doesn't remove duplicates

I have a generic class that is supposed to filter, order, project and paginate an IQueryable by calling this method:我有一个通用类,它应该通过调用此方法来过滤、排序、投影和分页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;
        }

I am calling Distinct() here我在这里调用Distinct()

        var projected = filtered
            .Select(converter)
            .Distinct();

to remove any duplicates that may appear after projection.删除投影后可能出现的任何重复项。

My assumption was that EF6 would generate something like我的假设是 EF6 会产生类似

SELECT DISTINCT Col1, Col2, Col3 FROM (SELECT Col1, Col2, Col3, Col4 FROM SOME_TABLE WHERE <some conditions on co1, col2, col3, col4 ...>)

ie that it would apply DISTINCT to the projection, so, if there are two rows with same col1, col2, col3 but different col4, only one row would make it into the result.即它会将DISTINCT应用于投影,因此,如果有两行具有相同的 col1、col2、col3 但 col4 不同,则只有一行会使其成为结果。 However, the SQL that I get looks like this:但是,我得到的 SQL 如下所示:

SELECT Col1, Col2, Col3, Col4 FROM (SELECT DISTINCT Col1, Col2, Col3, Col4 FROM SOME_TABLE)

- no projection, and DISTINCT is shifted into a subquery, as if I were doing this: - 没有投影,并且 DISTINCT 被转移到子查询中,就好像我在这样做:

var projected = filtered                    
                .Distinct()
                .Select(converter) 

I want this service to be a generic, ie potentially working with any TSource and TResult , but looks like there's some pitfall here and my understanding of what EF does is not correct.我希望这个服务是通用的,即可能与任何TSourceTResult一起工作,但看起来这里有一些陷阱,我对 EF 所做的事情的理解是不正确的。

What's going on here?这里发生了什么?

UPDATE更新

I believe the problem is in my converter.我相信问题出在我的转换器上。 I used the following function to generate the lambda expression passed to Select :我使用以下函数生成传递给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 is a join of providers, their rates and QAs. ProviderJoinRateAndQA是提供者、他们的费率和 QA 的连接。 Each Provider can have multiple services, rates and qas.每个Provider可以有多种服务、费率和质量保证。 In some cases I want view model to hide the rate and QA info.在某些情况下,我希望视图模型隐藏费率和 QA 信息。 I assumed I could do it by assigning a null to Rate and QA properties, but it doesn't seem to work: Distinct works incorrectly.我以为我可以通过为RateQA属性分配一个null来做到这一点,但它似乎不起作用: Distinct工作不正确。 After I replaced我换了之后
Rate = showRateAndQA ?费率 = showRateAndQA ? new QA { Grade = x.QA.Grade ... } : null with Rate = new QA { Grade = showRateAndQA ? new QA { Grade = x.QA.Grade ... } : 空,Rate = new QA { Grade = showRateAndQA ? x.QA.Grade : null ... }, x.QA.Grade : null ... },

Distinct worked correctly. Distinct工作正常。

Apparently EF didn't like my assigning null to object in my lambda.显然 EF 不喜欢我将null分配给我的 lambda 中的对象。

From memory, the default Distinct() implementation works by using the default Equals() method for the respective class, which is often unwanted (I've found this to be the case with my work atleast).从内存中,默认的Distinct()实现通过对相应类使用默认的Equals()方法来工作,这通常是不需要的(我发现至少我的工作就是这种情况)。

You need to set up something like the following;您需要进行如下设置;

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.
}

This should then allow the call to Distinct() to work properly.这应该允许对Distinct()的调用正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM