4

我有一个地址类。

public class Address : RootEntityBase
{
    virtual public string Province { set; get; }
    virtual public string City { set; get; }        
    virtual public string PostalCode { set; get; }
}

通过这个默认值:

var myList = new List<Address>
             {
               new Address {Province = "P1", City = "C1", PostalCode = "A"},
               new Address {Province = "P1", City = "C1", PostalCode = "B"},
               new Address {Province = "P1", City = "C1", PostalCode = "C"},

               new Address {Province = "P1", City = "C2", PostalCode = "D"},
               new Address {Province = "P1", City = "C2", PostalCode = "E"},

               new Address {Province = "P2", City = "C3", PostalCode = "F"},
               new Address {Province = "P2", City = "C3", PostalCode = "G"},
               new Address {Province = "P2", City = "C3", PostalCode = "H"},

               new Address {Province = "P2", City = "C4", PostalCode = "I"}
             };

我需要通过两列从这个 myList 中提取不同的内容:Province & City

即类似于myExpertResult

var myExpertResult = new List<Address>
                        {
                           new Address {Province = "P1", City = "C1"},
                           new Address {Province = "P1", City = "C2"},
                           new Address {Province = "P2", City = "C3"},
                           new Address {Province = "P2", City = "C4"}
                        }; 

所以我使用这段代码:

var list = myList.Select(x => new Address {City = x.City, Province = x.Province}).Distinct().ToList();

但我的结果无效,因为结果计数为 9,即所有地址。

SQL中的等效查询是:select distinct Province , City from tblAddress

我还通过 linq to NHibernate 测试了这个查询。

var q = SessionInstance.Query<Address>();
        .Select(x => new Address { Province = x.Province, City = x.City }).Distinct().ToList();

但它不支持此查询。异常消息是:Expression type 'NhDistinctExpression' is not supported by this SelectClauseVisitor.

我该怎么做?

4

3 回答 3

12

您可以使用GroupBy

var result = myList.GroupBy(a => new { a.Province, a.City })
      .Select(g => new Address { 
                  Province = g.Key.Province, 
                  City = g.Key.City 
              });

或者使用匿名类型:

 myList.Select(a => new { 
            Province = a.Province,
            City = a.City
        })
      .Distinct();

默认情况下,匿名类型使用值质量来比较,当所有属性都等价时,它是等价的。

另一种方法是在这里EqualityComparer使用另一个重载的客户ProvinceCity方法EqualGetHashCodeDistinct

于 2012-10-04T11:26:46.167 回答
0

也许这可以帮助:

一个简单的继电器比较器

public class RelayComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> equals;
private Func<T, int> getHashCode;  

public RelayComparer(Func<T, T, bool> equals, Func<T,int> getHashCode)
{
  this.equals = equals;
  this.getHashCode = getHashCode;
}

public bool Equals(T x, T y)
{
  return equals(x, y);
}

public int GetHashCode(T obj)
{
  return getHashCode(obj);
}
}


var comparer = new RelayComparer<Address>(
(lhs, rhs) => lhs.Province == rhs.Province && lhs.City == rhs.City, 
      t => t.Province.GetHashCode() + t.City.GetHashCode());

myList.Distinct(comparer);
于 2012-10-04T11:41:47.547 回答
0

如果您想要一种通过单个特定属性区分的通用方法,您可以使用以下方法:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;

  /// <summary> Gets property information.</summary>
  /// <exception cref="ArgumentException">
  ///   Thrown when one or more arguments have unsupported or illegal values.
  /// </exception>
  /// <typeparam name="TSource">   Type of the source. </typeparam>
  /// <typeparam name="TProperty"> Type of the property. </typeparam>
  /// <param name="source">         Source for the. </param>
  /// <param name="propertyLambda"> The property lambda. </param>
  /// <returns> The property information.</returns>
  public static PropertyInfo GetPropertyInfo<TSource, TProperty>(
      TSource source,
      Expression<Func<TSource, TProperty>> propertyLambda)
  {
     Type type = typeof(TSource);

     MemberExpression member = propertyLambda.Body as MemberExpression;
     if (member == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));
 PropertyInfo propInfo = member.Member as PropertyInfo;
 if (propInfo == null)
    throw new ArgumentException(string.Format(
        "Expression '{0}' refers to a field, not a property.",
        propertyLambda.ToString()));

 if (propInfo.ReflectedType != null && (type != propInfo.ReflectedType &&
                                        !type.IsSubclassOf(propInfo.ReflectedType)))
    throw new ArgumentException(string.Format(
        "Expresion '{0}' refers to a property that is not from type {1}.",
        propertyLambda.ToString(),
        type));

 return propInfo;
  }

      /// <summary> An IQueryable&lt;T&gt; extension method that distinct by a certain property.</summary>
      /// <exception cref="NullReferenceException"> Thrown when the underlying Session value was unexpectedly null. </exception>
      /// <typeparam name="T">  The result type of the IQueryable. </typeparam>
      /// <typeparam name="T1"> The property type. </typeparam>
      /// <param name="query">      The query to act on. </param>
      /// <param name="expression"> The expression, that references the property. </param>
      /// <returns> An IQueryable&lt;T&gt;</returns>
      public static IQueryable<T> DistinctBy<T, T1>(this IQueryable<T> query, Expression<Func<T, T1>> expression)
      {
         var distinctSelection = query.Select(expression);
         var info = GetPropertyInfo(default(T), expression);
         var propertyInfo = query.Provider.GetType().GetProperty("Session", BindingFlags.NonPublic | BindingFlags.Instance);
         if (propertyInfo == null)
         {
            throw new NullReferenceException("The underliying Session is not defined!");
         }
         ISession session = propertyInfo.GetValue(query.Provider, null) as ISession;
         var result = session.Query<T>().Where("x => @0.Contains( x." + info.Name + ")", distinctSelection);
         return result;
      }
   }

      /// <summary> An IQueryable&lt;T&gt; extension method that distinct by two properties (composite key).</summary>
      /// <exception cref="ArgumentNullException">  Thrown when one or more required arguments are null. </exception>
      /// <exception cref="NullReferenceException"> Thrown when a value was unexpectedly null. </exception>
      /// <typeparam name="T">  The resulting type. </typeparam>
      /// <typeparam name="T1"> The type of the first property. </typeparam>
      /// <typeparam name="T2"> The type of the second property. </typeparam>
      /// <param name="query">          The query to act on. </param>
      /// <param name="expressionKey1"> The first expression key (property 1 or key 1). </param>
      /// <param name="expressionKey2"> The second expression key (property 2 or key 2). </param>
      /// <returns> An IQueryable&lt;T&gt;</returns>
      public static IQueryable<T> DistinctBy<T, T1, T2>(this IQueryable<T> query, Expression<Func<T, T1>> expressionKey1, Expression<Func<T, T2>> expressionKey2)
      {
         if (expressionKey1 == null)
         {
            throw new ArgumentNullException("expressionKey1");
         }
         if (expressionKey2 == null)
         {
            return query.DistinctBy(expressionKey1);
         }
         var propertyInfo = query.Provider.GetType().GetProperty("Session", BindingFlags.NonPublic | BindingFlags.Instance);
         if (propertyInfo == null)
         {
            throw new NullReferenceException("The underliying Session is not defined!");
         }
         ISession session = propertyInfo.GetValue(query.Provider, null) as ISession;
         var info1 = GetPropertyInfo(default(T), expressionKey1);
         var info2 = GetPropertyInfo(default(T), expressionKey2);

         var result = session.Query<T>().Where("k => @0.Any(k1 => k1." + info1.Name + " == k." + info1.Name + " && k1." + info2.Name + " == k." + info2.Name + ")", query);

         return result;
      }

你可以这样称呼它:

var query = Session.Query<Person>().DistinctBy(p => p.FirstName);
于 2017-11-23T13:55:46.730 回答