ormlite-servicestack,C#,.net,Linq,ormlite Servicestack" /> ormlite-servicestack,C#,.net,Linq,ormlite Servicestack" />

C# 如果条件具有子查询,ServiceStack.OrmLite将失败

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") &&

由于.NETFramework4.0,我正在使用
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));
        }
    }
}