简体   繁体   English

LINQ 查询 - 如何参数化选择不同的查询

[英]LINQ Query - How to parameterize a select distinct query

I'm having a hard time figuring out what I am missing when trying to parameterize a "Select" with "Distinct" query.在尝试使用“Distinct”查询参数化“Select”时,我很难弄清楚我缺少什么。

This is a sample of the code I have repeated multiple times with different items to select.这是我使用不同项目重复多次的代码示例。

    private void getCustomerCodeList(ObservableCollection<Model> FilteredData)
    {
        var distCustomerCode = FilteredData.Select(i => new { i.CustomerCode, i.FamilyName }).Distinct().OrderBy(x => x.FamilyName).ToList();

        DistinctCustomerCodeList.Clear();

        foreach (var item in distCustomerCode)
        {
            DistinctCustomerCodeList.Add(new Model() { CustomerCode = item.CustomerCode, FamilyName = item.FamilyName });

        }

    }

I am trying to convert this into one method where I can pass in the "Select" and the "Orderby" as parameters.我正在尝试将其转换为一种方法,在该方法中我可以将“Select”和“Orderby”作为参数传递。 The code below is as far as I was able to get, and it works fine if I pass in a lambda with one property, but errors as soon as I try to add a second.下面的代码是我所能得到的,如果我传入一个具有一个属性的 lambda,它可以正常工作,但是一旦我尝试添加一个属性就会出错。

        public void getDistinct<TKey>(ObservableCollection<Model> FilteredData, Func<Model, TKey> myDistinctProperty, Func<TKey, TKey> mySortingProperty)
    {


        var distinct = FilteredData.Select(myDistinctProperty).Distinct().OrderBy(mySortingProperty).ToList();

        DistinctCustomerCodeList.Clear();

        foreach (var item in distinct )
        {

            DistinctCustomerCodeList.Add(new Model() { CustomerCode = item.ToString() });
        }
    }

If I call this method:如果我调用这个方法:

getDistinct<string>(FilteredData, x => x.CustomerCode, x => x);

it works fine but if I try:它工作正常,但如果我尝试:

getDistinct<string>(FilteredData, i => new { i.CustomerCode, i.FamilyName }, x => x.FamilyName)

it errors.它错误。

Can anyone shed some light on this for me.任何人都可以为我阐明这一点。

Thanks.谢谢。

Update-更新-

Here is the error message I am receiving.这是我收到的错误消息。

'IEnumerable' does not contain a definition for 'OrderBy' and the best extension method overload 'ParallelEnumerable.OrderBy<Model, string>(ParallelQuery, Func<Model, string>)' requires a receiver of type 'ParallelQuery' “IEnumerable”不包含“OrderBy”的定义,最佳扩展方法重载“ParallelEnumerable.OrderBy<Model, string>(ParallelQuery, Func<Model, string>)”需要“ParallelQuery”类型的接收器

I made the changes based on the clarification that nalpnir provided and here is what my updated code looks like.我根据nalpnir提供的说明进行了更改,这是我更新后的代码的样子。

       public void getDistinct<TKey>(ObservableCollection<Model> FilteredData, Func<Model, TKey> myDistinctProperty, Func<Model, string> mySortingProperty)
    {


        var distinct= FilteredData.Select(myDistinctProperty).Distinct().OrderBy(mySortingProperty).ToList();
        DistinctCustomerCodeList.Clear();
        foreach (var item in distinct)
        {

            DistinctCustomerCodeList.Add(new Model() { CustomerCode = item.ToString() });
        }
    }

This portion has the error provided above (FilteredData.Select(myDistinctProperty).Distinct())这部分有上面提供的错误 (FilteredData.Select(myDistinctProperty).Distinct())

and here is the updated method call:这是更新的方法调用:

getDistinct<Model>(FilteredData, i => new Model { FamilyName = i.FamilyName, CustomerCode = i.CustomerCode }, x => x.CustomerCode);

Update 2 -更新 2 -

Thank you all for your feedback.感谢大家的反馈。 I ended up using the answer from JeremyLakeman , as it fit best in the project I am working on.我最终使用了JeremyLakeman的答案,因为它最适合我正在从事的项目。

The answer from nalpnir is awesome and I will try to implement it in the future.来自nalpnir的答案很棒,我将在未来尝试实现它。

The reason is simple, the LINQ you are doing is wrong, for 2 reasons but the same reason itself:原因很简单,你做的 LINQ 是错误的,有两个原因,但同样的原因本身:

  • Your TKey is set as a string, so when you say new { i.CustomerCode, i.FamilyName } it doesnt know how to go from that expression to a string.您的 TKey 设置为字符串,因此当您说 new { i.CustomerCode, i.FamilyName } 时,它不知道如何从该表达式转换为字符串。

  • The same occurs in the case of the sorting, x is of type String, and x doesnt know what x.CustomerName is.排序的情况也是一样,x是String类型,x不知道x.CustomerName是什么。

What you should use is the Model as TKey, like this:您应该使用模型作为 TKey,如下所示:

getDistinct<Model>(list, i => new Model { FamilyName = i.FamilyName, CustomerCode = i.CustomerCode }, x => x.CustomerCode);

UPDATE: Since i noticed it didnt do what you wanted to do, which is to be able to get it without repetitions, I changed a bit the idea so you can get around it, and even made it more generic so you can implement it with any class you want, as long as you make a few changes which i ll explain更新:因为我注意到它没有做你想做的事情,即能够在不重复的情况下获得它,我改变了一点想法,这样你就可以绕过它,甚至使它更通用,这样你就可以实现它你想要的任何课程,只要你做一些改变,我会解释

public static List<T> getDistinct<T, TKey>(ObservableCollection<T> FilteredData, Func<T, TKey> myDistinctProperty, Func<T, string> mySortingProperty)
    where T:Model, new()
{
    var DistinctCustomerCodeList = new List<T>();

    var distinct = FilteredData.GroupBy(myDistinctProperty).Select(x => x.First()).OrderBy(mySortingProperty).ToList();

    foreach (var item in distinct)
    {
        DistinctCustomerCodeList.Add(new T() { CustomerCode = item.CustomerCode, FamilyName = item.FamilyName });
    }

    return DistinctCustomerCodeList;
}

As you see now you have 2 Generics, One is T which i restricted to be of type Model, and the other one is another type whichever you want in this particular case it will accept new { x.CustomerCode, x.FamilyName } .正如您现在看到的,您有 2 个泛型,一个是 T,我限制为 Model 类型,另一个是在这种特殊情况下您想要的另一种类型,它将接受new { x.CustomerCode, x.FamilyName } I ll give you a link to a .Net fiddle so you know can see a demo我会给你一个 .Net fiddle 的链接,所以你知道可以看到一个演示

Demo: demo演示:演示

You can toy with it.你可以玩弄它。 Basically whichever class you replace model for will work as long as you change the output of the type T, and change the Add inside the foreach.基本上,只要您更改类型 T 的输出并更改 foreach 中的 Add,您替换模型的任何类都将起作用。 Inherited members of Model will also work so lets say for example you implement the following: Model 的继承成员也可以使用,例如您实现以下内容:

public class ModelExtended:Model
{
    public int NewProp { get; set; }
}

And also changed the ObservableCollection To ObservableCollection will also work because they share some properties并且将 ObservableCollection 更改为 ObservableCollection 也将起作用,因为它们共享一些属性

The OrderBy() is expecting a generic type TKey but the parameter mySortingProperty is explicitly referencing Model . OrderBy()需要一个泛型类型TKey但参数mySortingProperty显式引用Model Update the parameter in your method definition as follows:更新方法定义中的参数,如下所示:

public void getDistinct<TKey>(ObservableCollection<Model> FilteredData, Func<Model, TKey> myDistinctProperty, Func<TKey, string> mySortingProperty)

Your first example turned each instance of Model into an anonymous type, then later back into a Model again.您的第一个示例将 Model 的每个实例转换为匿名类型,然后又重新转换为 Model。 Instead, the generic distinct method should create a new Model with only the requested fields.相反,通用的 distinct 方法应该创建一个只有请求字段的新模型。

public void getDistinct<TOrder>(ObservableCollection<Model> FilteredData, Func<Model, Model> distinct, Func<Model, TOrder> sort)
    {
        var distinct = FilteredData.Select(distinct).Distinct().OrderBy(sort).ToList();

        DistinctCustomerCodeList.Clear();
        DistinctCustomerCodeList.AddRange(distinct);
    }

Then this should work, with the compiler able to infer the generic types;那么这应该可以工作,编译器能够推断出泛型类型;

getDistinct(FilteredData, i => new Model{ i.CustomerCode, i.FamilyName }, x => x.FamilyName);

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

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