C# 如果条件具有子查询,ServiceStack.OrmLite将失败
由于.NETFramework4.0,我正在使用C# 如果条件具有子查询,ServiceStack.OrmLite将失败,c#,.net,linq,ormlite-servicestack,C#,.net,Linq,ormlite Servicestack,由于.NETFramework4.0,我正在使用ServiceStack.OrmLitev4.0.62。我需要执行搜索功能。由于我的POCO类有很深的层次结构,我需要将LINQ查询与嵌套子查询一起使用。例如: // some code is omitted Expression<Func<Person,bool>> condition = p => p.Name.Contains("John") &&
ServiceStack.OrmLite
v4.0.62。我需要执行搜索功能。由于我的POCO类有很深的层次结构,我需要将LINQ查询与嵌套子查询一起使用。例如:
// some code is omitted
Expression<Func<Person,bool>> condition = p => p.Name.Contains("John") &&
p.Addreses.Any(adr => adr.City.Contains("Moscow") &&
adr.Street.Contains("Yuri Gagarin") &&
adr.Building == 23); // and so on...
// some code is omitted
// Gets the quantity of records were found
public int GetCountBy(Expression<Func<T,bool>> condition)
{
// here it throws an Exception
return db.Persons.Count(condition);
}
当我们使用另一个支持表达式作为参数的方法时,会引发相同的异常。
我的问题是:
我怎样才能解决这个问题?
OrmLite支持这样的查询吗?据我所知,在我选择的OrmLite版本中没有这种可能性。但我发现,如果使用
Sql
class来表示内部lambda,则OrmLite支持它们。我们可以这样重写前面的示例:
Expression<Func<Person,bool>> condition = p => p.Name.Contains("John") &&
Sql.In(p.Id,
connection.From<Address>()
.Where(adr => adr.City.Contains("Moscow") &&
adr.Street.Contains("Yuri Gagarin") &&
adr.Building == 23)
.SelectDistinct(adr => adr.PersonId));
Expression condition=p=>p.Name.Contains(“John”)&&
Sql.In(p.Id,
连接
.Where(adr=>adr.City.Contains(“莫斯科”)&&
adr.Street.Contains(“Yuri Gagarin”)&&
adr.建筑物==23)
.SelectDistinct(adr=>adr.PersonId));
此外,我们还可以在地址中添加一些嵌套的lambda。所以我决定实现ExpressionVisitor类来重新映射lambdas。首先,我想展示我的PersonRepository类,它继承了标准IRepository接口的通用实现:
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Reestr.DAL.DB;
using Reestr.DAL.Entities;
using Reestr.DAL.Helpers;
using ServiceStack.OrmLite;
namespace Reestr.DAL.Repositories
{
internal class PersonRepository : Repository<Person>
{
private ReestrContext db;
private readonly MethodFinder finder;
/// <summary>
/// Инициализирует новый экземпляр класса <see cref="T:System.Object"/>.
/// </summary>
public PersonRepository(ReestrContext db) : base(db)
{
this.db = db;
finder = new MethodFinder(db);
}
public override Person GetById(long id)
{
Person p = base.GetById(id);
List<Dic> dics = db.Connection.Select<Dic>();
foreach (Subject subject in p.Subjects)
{
subject.Parent = dics.FirstOrDefault(dic => dic.DicCode == subject.ParentDicCode);
subject.Child = dics.FirstOrDefault(dic => dic.DicCode == subject.ChildDicCode);
}
return p;
}
public override long CountByCondition(Expression<System.Func<Person, bool>> predicate)
{
ResolveNestedConditions(predicate);
if (finder.IsNestedPocoExist)
{
return base.CountByCondition(finder.GetRegeneratedPredicate<Person>());
}
return base.CountByCondition(predicate);
}
public override IQueryable<Person> GetByCondition(Expression<System.Func<Person, bool>> predicate)
{
ResolveNestedConditions(predicate);
if (finder.IsNestedPocoExist)
{
return base.GetByCondition(finder.GetRegeneratedPredicate<Person>());
}
return base.GetByCondition(predicate);
}
public override IQueryable<Person> GetByCondition(Expression<System.Func<Person, bool>> predicate, int rows)
{
ResolveNestedConditions(predicate);
if (finder.IsNestedPocoExist)
{
return base.GetByCondition(finder.GetRegeneratedPredicate<Person>(), rows);
}
return base.GetByCondition(predicate, rows);
}
public override IQueryable<Person> GetByCondition(Expression<System.Func<Person, bool>> predicate, int? skip, int? rows)
{
ResolveNestedConditions(predicate);
if (finder.IsNestedPocoExist)
{
return base.GetByCondition(finder.GetRegeneratedPredicate<Person>(), skip, rows);
}
return base.GetByCondition(predicate, skip, rows);
}
private void ResolveNestedConditions(Expression<System.Func<Person, bool>> predicate)
{
finder.DoVisiting(predicate);
}
}
}
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
使用Reestr.DAL.DB;
使用Reestr.DAL.Entities;
使用Reestr.DAL.Helpers;
使用ServiceStack.OrmLite;
命名空间Reestr.DAL.Repositories
{
内部类PersonRepository:Repository
{
私有ReestrContext数据库;
私有只读MethodFinder;
///
/// Инициализирует новый экземпляр класса .
///
公共PersonRepository(ReestrContext数据库):基本(db)
{
这个.db=db;
查找器=新方法查找器(db);
}
公共覆盖人员GetById(长id)
{
Person p=base.GetById(id);
List dics=db.Connection.Select();
foreach(体育科目中的科目)
{
subject.Parent=dics.FirstOrDefault(dic=>dic.DicCode==subject.ParentDicCode);
subject.Child=dics.FirstOrDefault(dic=>dic.DicCode==subject.ChildDicCode);
}
返回p;
}
公共重写长CountByCondition(表达式谓词)
{
ResolveNestedConditions(谓词);
if(finder.IsNestedPocoExist)
{
返回base.CountByCondition(finder.GetRegeneratedPredicate());
}
返回base.CountByCondition(谓词);
}
公共重写IQueryable GetByCondition(表达式谓词)
{
ResolveNestedConditions(谓词);
if(finder.IsNestedPocoExist)
{
返回base.GetByCondition(finder.GetRegeneratedPredicate());
}
返回base.GetByCondition(谓词);
}
公共重写IQueryable GetByCondition(表达式谓词,int行)
{
ResolveNestedConditions(谓词);
if(finder.IsNestedPocoExist)
{
返回base.GetByCondition(finder.GetRegeneratedPredicate(),行);
}
返回base.GetByCondition(谓词,行);
}
公共重写IQueryable GetByCondition(表达式谓词、int?跳过、int?行)
{
ResolveNestedConditions(谓词);
if(finder.IsNestedPocoExist)
{
返回base.GetByCondition(finder.GetRegeneratedPredicate(),跳过,行);
}
返回base.GetByCondition(谓词、跳过、行);
}
私有void ResolveNestedConditions(表达式谓词)
{
finder.dovising(谓词);
}
}
}
以及负责重新映射的类:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Reestr.DAL.DB;
using Reestr.DAL.DataAnnotations;
using Reestr.DAL.Entities;
using ServiceStack.DataAnnotations;
using ServiceStack.OrmLite;
namespace Reestr.DAL.Helpers
{
/// <summary>
/// Класс для обработки входящего предиката на предмет генерации новых предикатов и выделения вложенных предикатов
/// </summary>
internal class MethodFinder : ExpressionVisitor
{
private Expression reGenNode;
// not best solution to put into this class this object...but...crutch variant
private ReestrContext db;
public MethodFinder(ReestrContext _db)
{
db = _db;
IsNestedPocoExist = false;
}
public void DoVisiting(Expression node)
{
reGenNode = Visit(node);
}
/// <summary>
/// Получает значение указывающее, что есть вложенные POCO объекты
/// </summary>
public bool IsNestedPocoExist { get; private set; }
/// <summary>
/// Получает новосгенерированный предикат, без использования вложенных предикатов
/// </summary>
/// <returns></returns>
public Expression<Func<T,bool>> GetRegeneratedPredicate<T>()
{
LambdaExpression le = reGenNode as LambdaExpression;
return Expression.Lambda<Func<T, bool>>(le.Body, le.Parameters);
}
/// <summary>
/// Просматривает дочерний элемент выражения <see cref="T:System.Linq.Expressions.MethodCallExpression"/>.
/// </summary>
/// <returns>
/// Измененное выражение в случае изменения самого выражения или любого его подвыражения; в противном случае возвращается исходное выражение.
/// </returns>
/// <param name="node">Выражение, которое необходимо просмотреть.</param>
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// статический метод расширения, возвращающий bool
if (node.Object == null && node.Method.IsGenericMethod && node.Method.ReturnType == typeof (bool))
{
var member = node.Arguments.FirstOrDefault(expression => expression.NodeType == ExpressionType.MemberAccess) as MemberExpression;
if (member != null)
{
var ePrimary = GenPrimaryKeyProperty(member);
// получаем вложенную лямбду с рекурсивным проходом
foreach (LambdaExpression lambda in node.Arguments.Where(expression => expression.NodeType == ExpressionType.Lambda))
{
if (lambda.Parameters[0].Type == typeof(Subject))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Subject>());
}
if (lambda.Parameters[0].Type == typeof(Photo))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Photo>());
}
if (lambda.Parameters[0].Type == typeof(Dic))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Dic>());
}
}
}
// "Вырезаем" вызов метода и заменяем на простейшее условие 1 == 1
//return Expression.Equal(Expression.Constant(1), Expression.Constant(1));
}
// обращение к вложенному POCO типу
MemberExpression me = node.Object as MemberExpression;
if (me != null)
{
LambdaExpression lambda = GenLambdaFromMethod(node);
if (lambda != null)
{
Type tExpr = GetInnerPocoExpressionType(me);
if (tExpr == typeof(Subject))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Subject>());
}
if (tExpr == typeof(Photo))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Photo>());
}
if (tExpr == typeof(Dic))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Dic>());
}
}
}
Visit(node.Arguments);
return node;
}
/// <summary>
/// Получает лямбду из свойства пользовательского типа внутреннего объекта
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
private LambdaExpression GenLambdaFromMethod(MethodCallExpression method)
{
MemberExpression me = method.Object as MemberExpression;
Type tExpr = GetInnerPocoExpressionType(me);
ParameterExpression pe = Expression.Parameter(me.Expression.Type, me.Expression.Type.Name.ToLower());
Expression property = Expression.Property(pe, pe.Type.GetProperties().First(pi => pi.Name == me.Member.Name));
if (tExpr == typeof (Subject) ||
tExpr == typeof(Photo) ||
tExpr == typeof(Dic))
{
Expression regenMember = Expression.Call(property, method.Method, method.Arguments);
LambdaExpression le = Expression.Lambda(regenMember, pe);
return le;
}
return null;
}
/// <summary>
/// Получает корневой тип объекта
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private Type GetInnerPocoExpressionType(MemberExpression me)
{
MemberExpression meNested = me.Expression as MemberExpression;
if (meNested == null)
{
return me.Type;
}
return GetInnerPocoExpressionType(meNested);
}
/// <summary>
/// Получает последний вложенный POCO объект, например {person} или {dic}, если является свойством POCO класса
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private Expression GetInnerPocoExpression(MemberExpression me)
{
MemberExpression meNested = me.Expression as MemberExpression;
if (meNested == null)
{
return me.Expression;
}
return GetInnerPocoExpression(meNested);
}
/// <summary>
/// Получаем свойство класса, которое является POCO классом по внешнему ключу например для Person: p => p.Id
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private MemberExpression GenPrimaryKeyProperty(MemberExpression me)
{
// POCO выражение
var mConverted = GetInnerPocoExpression(me);
// берем свойство с атрибутом PrimaryKey или костыль для типа Subject
// для предмета у нас не id используется а ChildDicCode (PCode), который является ключом к DicCode таблицы Dic
var primaryProperty = mConverted.Type.GetProperties()
.FirstOrDefault(info => info.GetCustomAttributes(mConverted.Type == typeof(Subject) ? typeof(CustomPrimaryKeyAttribute) : typeof(PrimaryKeyAttribute), false).Any());
// формируем обращение к свойству, используя уже имеющийся параметр
var ePrimary = Expression.Property(mConverted, mConverted.Type.GetProperty(primaryProperty.Name, primaryProperty.PropertyType));
return ePrimary;
}
/// <summary>
/// Возвращает сгенерированную лямбду по внешнему ключу например для Subject: subj => subj.PersonId
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private Expression<Func<T, object>> GetFieldLambda<T>()
{
ParameterExpression pePoco = Expression.Parameter(typeof (T), typeof (T).Name.ToLower());
var referProperty =
typeof (T).GetProperties()
.FirstOrDefault(
info => info.GetCustomAttributes(typeof (CustomForeignKeyAttribute), false).Any());
var eReference = Expression.Property(pePoco,
typeof (T).GetProperty(referProperty.Name, referProperty.PropertyType));
return Expression.Lambda<Func<T, object>>(Expression.Convert(eReference, typeof (object)), pePoco);
}
/// <summary>
/// Возвращает перегенерированную лямбду в виде обращения к статическому методу класса Sql: Sql.In([nested POCO lambda])
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="primary">обращение к свойству POCO объекта</param>
/// <param name="whereL">сгенерированная лямбда работы с внутренним обїектом</param>
/// <param name="field">лямба доступа к полю внешнего ключа объекта</param>
/// <returns></returns>
private Expression GenerateSqlInExpression<T>(MemberExpression primary, LambdaExpression whereL, Expression<Func<T,object>> field)
{
IsNestedPocoExist = true;
// ищём вложенные лямбды и если нашли добавляем в коллекцию классов новосозданный класс
var finder = new MethodFinder(db);
var rebuiltE = finder.Visit(whereL);
Expression<Func<T, bool>> inWhere = Expression.Lambda<Func<T, bool>>((rebuiltE as LambdaExpression).Body, whereL.Parameters);
SqlExpression<T> eSqlbody = db.Connection.From<T>().Where(inWhere).SelectDistinct(field);
MethodInfo mIn = typeof (Sql).GetMethods()
.Where(mi => mi.Name == "In")
.First(mi => mi.GetParameters().Any(pi => pi.ParameterType.Name == typeof (SqlExpression<>).Name))
.MakeGenericMethod(primary.Type, typeof(T));
return Expression.Call(mIn, primary, Expression.Constant(eSqlbody));
}
}
}
使用系统;
使用System.Linq;
使用System.Linq.Expressions;
运用系统反思;
使用Reestr.DAL.DB;
使用Reestr.DAL.DataAnnotations;
使用Reestr.DAL.Entities;
使用ServiceStack.DataAnnotations;
使用ServiceStack.OrmLite;
命名空间Reestr.DAL.Helpers
{
///
/// Класс для обработки входящего предиката на предмет генерации новых предикатов и выделения вложенных предикатов
///
内部类MethodFinder:ExpressionVisitor
{
私有表达式节点;
//不是将这个对象放入这个类的最佳解决方案…但是…拐杖变体
私有ReestrContext数据库;
公共MethodFinder(ReestrContext_db)
{
db=_db;
IsNestedPocoExist=false;
}
公共void(表达式节点)
{
reGenNode=访问(节点);
}
///
///这是一个很好的例子
///
公共布尔是嵌套的pocoexist{get;private set;}
///
/// Получает новосгенерированный предикат, без использования вложенных предикатов
///
///
公共表达式GetRegeneratedPredicate()
{
LambdaExpression le=作为LambdaExpression重新生成节点;
返回表达式Lambda(le.Body,le.Parameters);
}
///
/// Просматривает дочерний элемент выражения .
///
///
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Reestr.DAL.DB;
using Reestr.DAL.DataAnnotations;
using Reestr.DAL.Entities;
using ServiceStack.DataAnnotations;
using ServiceStack.OrmLite;
namespace Reestr.DAL.Helpers
{
/// <summary>
/// Класс для обработки входящего предиката на предмет генерации новых предикатов и выделения вложенных предикатов
/// </summary>
internal class MethodFinder : ExpressionVisitor
{
private Expression reGenNode;
// not best solution to put into this class this object...but...crutch variant
private ReestrContext db;
public MethodFinder(ReestrContext _db)
{
db = _db;
IsNestedPocoExist = false;
}
public void DoVisiting(Expression node)
{
reGenNode = Visit(node);
}
/// <summary>
/// Получает значение указывающее, что есть вложенные POCO объекты
/// </summary>
public bool IsNestedPocoExist { get; private set; }
/// <summary>
/// Получает новосгенерированный предикат, без использования вложенных предикатов
/// </summary>
/// <returns></returns>
public Expression<Func<T,bool>> GetRegeneratedPredicate<T>()
{
LambdaExpression le = reGenNode as LambdaExpression;
return Expression.Lambda<Func<T, bool>>(le.Body, le.Parameters);
}
/// <summary>
/// Просматривает дочерний элемент выражения <see cref="T:System.Linq.Expressions.MethodCallExpression"/>.
/// </summary>
/// <returns>
/// Измененное выражение в случае изменения самого выражения или любого его подвыражения; в противном случае возвращается исходное выражение.
/// </returns>
/// <param name="node">Выражение, которое необходимо просмотреть.</param>
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// статический метод расширения, возвращающий bool
if (node.Object == null && node.Method.IsGenericMethod && node.Method.ReturnType == typeof (bool))
{
var member = node.Arguments.FirstOrDefault(expression => expression.NodeType == ExpressionType.MemberAccess) as MemberExpression;
if (member != null)
{
var ePrimary = GenPrimaryKeyProperty(member);
// получаем вложенную лямбду с рекурсивным проходом
foreach (LambdaExpression lambda in node.Arguments.Where(expression => expression.NodeType == ExpressionType.Lambda))
{
if (lambda.Parameters[0].Type == typeof(Subject))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Subject>());
}
if (lambda.Parameters[0].Type == typeof(Photo))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Photo>());
}
if (lambda.Parameters[0].Type == typeof(Dic))
{
return GenerateSqlInExpression(ePrimary, lambda, GetFieldLambda<Dic>());
}
}
}
// "Вырезаем" вызов метода и заменяем на простейшее условие 1 == 1
//return Expression.Equal(Expression.Constant(1), Expression.Constant(1));
}
// обращение к вложенному POCO типу
MemberExpression me = node.Object as MemberExpression;
if (me != null)
{
LambdaExpression lambda = GenLambdaFromMethod(node);
if (lambda != null)
{
Type tExpr = GetInnerPocoExpressionType(me);
if (tExpr == typeof(Subject))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Subject>());
}
if (tExpr == typeof(Photo))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Photo>());
}
if (tExpr == typeof(Dic))
{
return GenerateSqlInExpression(GenPrimaryKeyProperty(me), lambda, GetFieldLambda<Dic>());
}
}
}
Visit(node.Arguments);
return node;
}
/// <summary>
/// Получает лямбду из свойства пользовательского типа внутреннего объекта
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
private LambdaExpression GenLambdaFromMethod(MethodCallExpression method)
{
MemberExpression me = method.Object as MemberExpression;
Type tExpr = GetInnerPocoExpressionType(me);
ParameterExpression pe = Expression.Parameter(me.Expression.Type, me.Expression.Type.Name.ToLower());
Expression property = Expression.Property(pe, pe.Type.GetProperties().First(pi => pi.Name == me.Member.Name));
if (tExpr == typeof (Subject) ||
tExpr == typeof(Photo) ||
tExpr == typeof(Dic))
{
Expression regenMember = Expression.Call(property, method.Method, method.Arguments);
LambdaExpression le = Expression.Lambda(regenMember, pe);
return le;
}
return null;
}
/// <summary>
/// Получает корневой тип объекта
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private Type GetInnerPocoExpressionType(MemberExpression me)
{
MemberExpression meNested = me.Expression as MemberExpression;
if (meNested == null)
{
return me.Type;
}
return GetInnerPocoExpressionType(meNested);
}
/// <summary>
/// Получает последний вложенный POCO объект, например {person} или {dic}, если является свойством POCO класса
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private Expression GetInnerPocoExpression(MemberExpression me)
{
MemberExpression meNested = me.Expression as MemberExpression;
if (meNested == null)
{
return me.Expression;
}
return GetInnerPocoExpression(meNested);
}
/// <summary>
/// Получаем свойство класса, которое является POCO классом по внешнему ключу например для Person: p => p.Id
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
private MemberExpression GenPrimaryKeyProperty(MemberExpression me)
{
// POCO выражение
var mConverted = GetInnerPocoExpression(me);
// берем свойство с атрибутом PrimaryKey или костыль для типа Subject
// для предмета у нас не id используется а ChildDicCode (PCode), который является ключом к DicCode таблицы Dic
var primaryProperty = mConverted.Type.GetProperties()
.FirstOrDefault(info => info.GetCustomAttributes(mConverted.Type == typeof(Subject) ? typeof(CustomPrimaryKeyAttribute) : typeof(PrimaryKeyAttribute), false).Any());
// формируем обращение к свойству, используя уже имеющийся параметр
var ePrimary = Expression.Property(mConverted, mConverted.Type.GetProperty(primaryProperty.Name, primaryProperty.PropertyType));
return ePrimary;
}
/// <summary>
/// Возвращает сгенерированную лямбду по внешнему ключу например для Subject: subj => subj.PersonId
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private Expression<Func<T, object>> GetFieldLambda<T>()
{
ParameterExpression pePoco = Expression.Parameter(typeof (T), typeof (T).Name.ToLower());
var referProperty =
typeof (T).GetProperties()
.FirstOrDefault(
info => info.GetCustomAttributes(typeof (CustomForeignKeyAttribute), false).Any());
var eReference = Expression.Property(pePoco,
typeof (T).GetProperty(referProperty.Name, referProperty.PropertyType));
return Expression.Lambda<Func<T, object>>(Expression.Convert(eReference, typeof (object)), pePoco);
}
/// <summary>
/// Возвращает перегенерированную лямбду в виде обращения к статическому методу класса Sql: Sql.In([nested POCO lambda])
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="primary">обращение к свойству POCO объекта</param>
/// <param name="whereL">сгенерированная лямбда работы с внутренним обїектом</param>
/// <param name="field">лямба доступа к полю внешнего ключа объекта</param>
/// <returns></returns>
private Expression GenerateSqlInExpression<T>(MemberExpression primary, LambdaExpression whereL, Expression<Func<T,object>> field)
{
IsNestedPocoExist = true;
// ищём вложенные лямбды и если нашли добавляем в коллекцию классов новосозданный класс
var finder = new MethodFinder(db);
var rebuiltE = finder.Visit(whereL);
Expression<Func<T, bool>> inWhere = Expression.Lambda<Func<T, bool>>((rebuiltE as LambdaExpression).Body, whereL.Parameters);
SqlExpression<T> eSqlbody = db.Connection.From<T>().Where(inWhere).SelectDistinct(field);
MethodInfo mIn = typeof (Sql).GetMethods()
.Where(mi => mi.Name == "In")
.First(mi => mi.GetParameters().Any(pi => pi.ParameterType.Name == typeof (SqlExpression<>).Name))
.MakeGenericMethod(primary.Type, typeof(T));
return Expression.Call(mIn, primary, Expression.Constant(eSqlbody));
}
}
}