C# 如何在linq&;通过某些列将linq转换为NHibernate
我有一个地址类C# 如何在linq&;通过某些列将linq转换为NHibernate,c#,linq,distinct,linq-to-nhibernate,C#,Linq,Distinct,Linq To Nhibernate,我有一个地址类 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>
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"}
};
所以我使用这个代码:
var list = myList.Select(x => new Address {City = x.City, Province = x.Province}).Distinct().ToList();
但我的结果无效,因为结果的计数是9,即所有地址
SQL中的等价查询是:从tblAddress中选择不同的省、市
我还通过linq对NHibernate测试了这个查询
var q = SessionInstance.Query<Address>();
.Select(x => new Address { Province = x.Province, City = x.City }).Distinct().ToList();
var q=SessionInstance.Query();
.Select(x=>新地址{Province=x.Province,City=x.City}).Distinct().ToList();
但它不支持这个查询。异常消息是:此SelectClauseVisitor不支持表达式类型“NhDistinctExpression”。
我怎么做?您可以使用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
,它使用省
和市
进行相等
和获取hashcode
方法,并在中使用另一个重载不同的
,这可能有助于:
一个简单的继电器比较器
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);
公共类RelayComparer:IEqualityComparer
{
私有函数等于;
私有Func getHashCode;
公共中继比较程序(Func equals,Func getHashCode)
{
this.equals=equals;
this.getHashCode=getHashCode;
}
公共布尔等于(TX,TY)
{
返回等于(x,y);
}
公共int GetHashCode(T obj)
{
返回getHashCode(obj);
}
}
var比较器=新继电器比较器(
(左,右)=>左。省==右。省和左。市==右。市,
t=>t.Province.GetHashCode()+t.City.GetHashCode());
myList.Distinct(比较器);
如果您想要一种通过单个特定属性进行区分的通用方法,您可以使用以下方法:
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<T> 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<T></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<T> 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<T></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;
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Linq;
使用System.Linq.Dynamic.Core;
使用System.Linq.Expressions;
///获取属性信息。
///
///当一个或多个参数的值不受支持或非法时引发。
///
///源的类型。
///属性的类型。
///资料来源。
///lambda的财产。
///属性信息。
公共静态属性信息GetPropertyInfo(
t来源:,
表达式属性(MBDA)
{
类型类型=类型(t源);
MemberExpression member=propertyLambda.Body作为MemberExpression;
if(成员==null)
抛出新ArgumentException(string.Format(
表达式“{0}”引用的是方法,而不是属性,
propertyLambda.ToString());
PropertyInfo-propInfo=成员。成员为PropertyInfo;
if(propInfo==null)
抛出新ArgumentException(string.Format(
表达式“{0}”引用的是字段,而不是属性,
propertyLambda.ToString());
如果(propInfo.ReflectedType!=null&&(type!=propInfo.ReflectedType&&
!type.IsSubclassOf(propInfo.ReflectedType)))
抛出新ArgumentException(string.Format(
表达式{0}引用的属性不是来自类型{1},
propertyLambda.ToString(),
类型);
返回propInfo;
}
///一种iQueryTablet扩展方法,它通过特定属性进行区分。
///当基础会话值意外为空时引发。
///IQueryable的结果类型。
///属性类型。
///要对其执行操作的查询。
///引用属性的表达式。
///白兰地
公共静态IQueryable DistinctBy(此IQueryable查询,表达式)
{
var distinctSelection=query.Select(表达式);
var info=GetPropertyInfo(默认值(T),表达式);
var propertyInfo=query.Provider.GetType().GetProperty(“会话”,BindingFlags.NonPublic | BindingFlags.Instance);
如果(propertyInfo==null)
{
抛出新的NullReferenceException(“未定义基础会话!”);
}
ISession session=propertyInfo.GetValue(query.Provider,null)作为ISession;
var result=session.Query()。其中(“x=>@0.Contains(x.“+info.Name+”),distinctSelection);
返回结果;
}
}
///由两个属性(复合键)区分的iQueryTablet扩展方法。
///当一个或多个必需参数为null时引发。
///值意外为null时引发。
///结果类型。
///第一个属性的类型。
///第二个属性的类型。
///要对其执行操作的查询。
///第一个表达式键(属性1或键1)。
///第二个表达式键(属性2或键2)。
///白兰地
公共静态IQueryable DistinctBy(此IQueryable查询,表达式expressionKey1,表达式expressionKey2)
{
if(expressionKey1==null)
{
抛出新ArgumentNullException(“expressionKey1”);
}
if(expressionKey2==null)
{
返回query.DistinctBy(expressionKey1);
}
var propertyInfo=query.Provider.GetType().GetProperty(“会话”,BindingFlags.NonPublic | BindingFlags.Instance);
如果(propertyInfo==null)
{
抛出新的NullReferenceException(“未定义基础会话!”);
}
ISession session=propertyInfo.GetValue(query.Provider,null)作为ISession;
var info1=GetPropertyInfo(默认值(T),expressionKey1);
var info2=GetPropertyInfo(默认值(T),expressionKey2);
var result=session.Query()。其中(“k=>@0.Any(k1=>k1.+info1.Name+”==k.“+info1.Name+”&&k1.+info2.Name+”==k.+info2.Name+”),Query);
返回结果;
}
你可以这样称呼它:
var query = Session.Query<Person>().DistinctBy(p => p.FirstName);
var query=Session.query(
var query = Session.Query<Person>().DistinctBy(p => p.FirstName);