powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate 3 и Specification pattern
4 сообщений из 4, страница 1 из 1
NHibernate 3 и Specification pattern
    #37064603
stuffhappens
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.
При попытке использовать Specification pattern с NHibernate выкидывает исключение
Код: plaintext
Не удалось привести тип объекта "NHibernate.Hql.Ast.HqlBitwiseAnd" к типу "NHibernate.Hql.Ast.HqlBooleanExpression"
.

вот так реализован AndSpecification:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
    internal class AndSpecification<TEntity> : ISpecification<TEntity>
    {
        private ISpecification<TEntity> spec1;
        private ISpecification<TEntity> spec2;

        internal AndSpecification(ISpecification<TEntity> s1, ISpecification<TEntity> s2)
        {
            spec1 = s1;
            spec2 = s2;
        }

        public Expression<Func<TEntity, bool>> Predicate
        {
            get 
            {
                return spec1.Predicate.And(spec2.Predicate);
            }
        }
    }

And - это Extension-метод
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
    public static class Utility
    {
        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // build parameter map (from parameters of second to parameters of first)
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with parameters from the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // apply composition of lambda expression bodies to parameters from the first expression 
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.And);
        }
    }

Реализация ParameterRebinder:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
    public class ParameterRebinder : ExpressionVisitor
    {
        private readonly Dictionary<ParameterExpression, ParameterExpression> map;

        public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
        {
            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
        }

        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
        {
            return new ParameterRebinder(map).Visit(exp);
        }

        protected override Expression VisitParameter(ParameterExpression p)
        {
            ParameterExpression replacement;

            if (map.TryGetValue(p, out replacement))
                p = replacement;

            return base.VisitParameter(p);
        }
    }
Проблема возникает при вызове вот такой конструкции:
Код: plaintext
 ISession.Query<T>().Where(AndSpecification<T>.Predicate)
Спецификации, которые объединяются посредством AndSpecification, по-отдельности работают корректно.

Буду благодарен, если поможете разобраться с проблемой!
...
Рейтинг: 0 / 0
NHibernate 3 и Specification pattern
    #37064706
stuffhappens
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
stuffhappens,

Проблема свелась к следующему. Путь есть класс:
Код: plaintext
1.
2.
3.
4.
5.
6.
    public class Test
    {
        public virtual int ID { get; set; }
        public virtual string Text { get; set; }
        public virtual int Number { get; set; }
    }
когда я создаю Expression tree следующим образом
Код: plaintext
Expression<Func<Test, bool>> predicate1 = x => x.Text.Length > 5 && x.Number > 0;
То в debug view получаю следующее:
Код: plaintext
1.
2.
.Lambda #Lambda1<System.Func`2[NHLinqTest.Test,System.Boolean]>(NHLinqTest.Test $x) {
    ($x.Text).Length > 5 && $x.Number > 0
}
Обратите внимание на использование оператора &&. Когда я создаю Expression tree следующим образом
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
 var y = Expression.Parameter(typeof(Test));

            var predicate2 = Expression.And(
                Expression.GreaterThan(
                    Expression.Property(Expression.Property(y, "Text"), "Length"),
                    Expression.Constant(5)),
            Expression.GreaterThan(
                Expression.Property(y, "Number"),
                    Expression.Constant(0)));
то в debug view получаю
Код: plaintext
($var1.Text).Length > 5 & $var1.Number > 0
обратите внимание на & вместо &&. Почему во втором случае я получаю битовое и??? Что нужно поправить в predicate2, чтобы получать логическое и?
Спасибо!
...
Рейтинг: 0 / 0
NHibernate 3 и Specification pattern
    #37064762
stuffhappens
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
stuffhappens,

Проблема решена окончательно. Expression.And - реально битовая операция! Expression.AndAlso - то, что нужно.
...
Рейтинг: 0 / 0
NHibernate 3 и Specification pattern
    #37107900
KirillMedvedev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот еще фреймворк по теме...
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate 3 и Specification pattern
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]