Linq / EF动态组由可选参数组成

时间:2014-10-06 08:55:53

标签: c# linq entity-framework

我的搜索/群组功能出现问题。

上下文

我有一个客户对象列表(实体框架上下文),我想在此列表中找到所有可能的重复项。如果对象是重复的标准应该是动态的。让我们说可以通过UI选择。

模型

让我们假设以下部分。

我的CustomerClass

public class Customer
{
    public int CustomerId { get; set; }
    public string SearchName { get; set; }
    public string Mail { get; set; }
    public DateTime? Birthday { get; set; }
    public string CardNumber { get; set; }
    public DateTime Created { get; set; }
}

重复的可能标准是:SearchName,Mail,Birthday和CardNumber。

以下函数返回适当的结果:

    public IList<Customer> GetPossibleDuplicates()
    {
        IList<Customer> list;

        list =
            (from s in this.Context.Customers
                group s by new
                           {
                               s.SearchName, 
                               s.CardNumber
                           }
                into g where g.Count() > 1 select g)
                .SelectMany(g => g)
                .OrderBy(o => o.SearchName)
                .ThenBy(c => c.Created)
                .ToList();


        return list;
    }

我遇到的问题是按照声明制作小组&#34;动态&#34;所以根据选定的creteria进行分组。有什么好的解决方案的建议吗?

3 个答案:

答案 0 :(得分:0)

Enumerable.GroupBy允许IEqualityComparer的参数。请参阅the MSDN page

此比较器可能是查询的动态部分。您声明分组基于选择标准,因此这将为您提供:

public IList<Customer> GetPossibleDuplicates()
{
    var comparer = SomeMethodReturningAnEqualityComparerBasedOnSelectionCriteria();
    return this.Context.Customers
            .GroupBy(customer => customer, comparer)
            .SelectMany(g => g)
            .OrderBy(o => o.SearchName)
            .ThenBy(c => c.Created)
            .ToList();
}

返回比较器的方法将返回IEqualityComparer<Customer>

答案 1 :(得分:0)

如何依赖围绕IComparable

构建的标准
Func<Customer, IComparable> criteria

并且封装在方法中的查询看起来像这样

public IList<Customer> FindByCriteria(Func<Customer, IComparable> criteria)
{
    var query = from customer in FindAll()
                group customer by criteria(customer)
                into groups
                where groups.Count() > 1
                from item in groups
                orderby item.SearchName, item.Created
                select item;

    return query.ToList();
}

然后,您可以使用自己的数据结构,甚至使用Tuple

void Main()
{
    var repository = new Repository();

    //Find all
    repository.FindAll().Dump();

    // Find by mail
    var mail = new Func<Customer, IComparable>(customer =>
    {
        return Tuple.Create(customer.Mail);
    });
    repository
        .FindByCriteria(mail)
        .Dump();

    // Find by mail and card number
    var multi = new Func<Customer, IComparable>(customer =>
    {
        return Tuple.Create(customer.CardNumber, customer.Mail);
    });
    repository
        .FindByCriteria(multi)
        .Dump();
}

完整的存储库代码如下所示

public class Repository
{
    public IList<Customer> FindByCriteria(Func<Customer, IComparable> criteria)
    {
        var query = from customer in FindAll()
                    group customer by criteria(customer)
                    into groupings
                    where groupings.Count() > 1
                    from grouping in groupings
                    orderby grouping.SearchName, grouping.Created
                    select grouping;

        return query.ToList();
    }

    public IEnumerable<Customer> FindAll()
    {
        yield return new Customer
        {
            CustomerId = 1,
            SearchName = "John",
            CardNumber = "0000 0000 0000 0000 1",
            Mail = "john.doe@test.com",
        };

        yield return new Customer
        {
            CustomerId = 2,
            SearchName = "Jim",
            CardNumber = "0000 0000 0000 0000 2",
            Mail = "jim.doe@test.com",
        };

        yield return new Customer
        {
            CustomerId = 3,
            SearchName = "Jack",
            CardNumber = "0000 0000 0000 0000 3",
            Mail = "jack.doe@test.com",
        };

        yield return new Customer
        {
            CustomerId = 4,
            SearchName = "Jane",
            CardNumber = "0000 0000 0000 0000 3",
            Mail = "john.doe@test.com",
        };

        yield return new Customer
        {
            CustomerId = 4,
            SearchName = "Joan",
            CardNumber = "0000 0000 0000 0000 3",
            Mail = "john.doe@test.com",
        };
    }
}

答案 2 :(得分:-1)

您的查询可以重写为:

var result = this.Context.Customers
    .GroupBy(x => new { x.SearchName, x.CardNumber })
    .Where(x => x.Count() > 1)
    .SelectMany(x => x)
    .OrderBy(x => x.SearchName)
    .ThenBy(x => x.Created)
    .ToList();

您可以看到.GroupBy(...)调用采用Expression<Func<Customer, TKey>>类型的表达式,其中TKey是匿名类型。因此,如果您可以设法动态生成表达式,那么您可以解决问题。

我必须承认匿名类型是由编译器创建的,因此您的C#代码中还没有该类型。

相关问题