Внедрение гибкой инфраструктуры поиска с использованием nHibernate - PullRequest
0 голосов
/ 31 марта 2011

Моя цель - реализовать довольно общий механизм поиска. Вот общая идея:
Вы можете осуществлять поиск по любому свойству объекта, который ищете (например, по зарплате сотрудника, по названию отдела и т. д.).
Каждое свойство, по которому вы можете искать, представлено классом, который наследуется от EntityProperty:

public abstract class EntityProperty<T>
        where T:Entity
    {
        public enum Operator
        {
            In,
            NotIn,
        }

        /// <summary>
        /// Name of the property
        /// </summary>
        public abstract string Name { get; }
        //Add a search term to the given query, using the given values
        public abstract IQueryable<T> AddSearchTerm(IQueryable<T> query, IEnumerable<object> values);

        public abstract IQueryable<T> AddSortingTerm(IQueryable<T> query);


        protected Operator _operator = Operator.In;
        protected bool _sortAscending = false;

        public EntityProperty(Operator op)
        {
            _operator = op;
        }

        //use this c'tor if you're using the property for sorting only
        public EntityProperty(bool sortAscending)
        {
            _sortAscending = sortAscending;
        }
    }

все свойства, которые вы ищете / сортируете, хранятся в простом классе коллекции:

public class SearchParametersCollection<T>
        where T: Entity
    {

        public IDictionary<EntityProperty<T>,IEnumerable<object>> SearchProperties { get; private set; }
        public IList<EntityProperty<T>> SortProperties { get; private set; }

        public SearchParametersCollection()
        {
            SearchProperties = new Dictionary<EntityProperty<T>, IEnumerable<object>>();
            SortProperties = new  List<EntityProperty<T>>();
        }

        public void AddSearchProperty(EntityProperty<T> property, IEnumerable<object> values)
        {
            SearchProperties.Add(property, values);
        }

        public void AddSortProperty(EntityProperty<T> property)
        {
            if (SortProperties.Contains(property))
            {
                throw new ArgumentException(string.Format("property {0} already exists in sorting order", property.Name));
            }
            SortProperties.Add(property);
        }


    }

Теперь все, что должен делать класс репозитория:

protected IEnumerable<T> Search<T>(SearchParametersCollection<T> parameters)
            where T : Entity
        {
            IQueryable<T> query = this.Session.Linq<T>();
            foreach (var searchParam in parameters.SearchProperties)
            {
                query = searchParam.Key.AddSearchTerm(query, searchParam.Value);
            }

            //add order
            foreach (var sortParam in parameters.SortProperties)
            {
                query = sortParam.AddSortingTerm(query);
            }

            return query.AsEnumerable();
        }

например, вот класс, который реализует поиск пользователя по его полному имени:

public class UserFullName : EntityProperty<User>
    {

        public override string Name
        {
            get { return "Full Name"; }
        }

        public override IQueryable<User> AddSearchTerm(IQueryable<User> query, IEnumerable<object> values)
        {
            switch (_operator)
            {
                case Operator.In:
                    //btw- this doesn't work with nHibernate... :(
                    return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) > 0));
                case Operator.NotIn:
                    return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) == 0));
                default:
                    throw new InvalidOperationException("Unrecognized operator " + _operator.ToString());
            }

        }

        public override IQueryable<User> AddSortingTerm(IQueryable<User> query)
        {
            return (_sortAscending) ? query.OrderBy(u => u.FullName) : query.OrderByDescending(u => u.FullName);
        }


        public UserFullName(bool sortAscending)
            : base(sortAscending)
        {

        }

        public UserFullName(Operator op)
            : base(op)
        {

        }
    }

мои вопросы:
1. во-первых, я даже на правильном пути? Я не знаю ни одного известного метода достижения того, чего я хочу, но я могу ошибаться ...
2. мне кажется, что классы Properties должны быть на уровне домена, а не в DAL, так как я бы хотел, чтобы уровни контроллера могли использовать их. Однако это мешает мне использовать любую специфичную для nHibernate реализацию поиска (то есть любой другой интерфейс, кроме Linq). Кто-нибудь может придумать решение, которое позволило бы мне использовать всю мощь nH, сохраняя эти классы видимыми для верхних уровней? Я думал о том, чтобы перенести их в проект «Общий», но «Общий» не знает о сущностях Модели, и я бы хотел, чтобы это продолжалось.
3. как вы можете видеть из моего комментария к методу AddSearchTerm - я действительно не смог реализовать оператор «in», используя nH (я использую nH 2.1.2 с провайдером Linq). любые предложения в этом отношении будут оценены. (см. также мой вопрос со вчерашнего дня ).
Спасибо!

Ответы [ 2 ]

1 голос
/ 31 марта 2011

Если вам нужен хороший API для запроса объектов NHIbernate, вам следует использовать ICriteria (для NH 2.x) или QueryOver (для NH 3.x).

Вы слишком усложняете DAL этими поисками. У Айенде есть хорошая запись о почему вы не должны это делать

0 голосов
/ 30 июня 2012

В итоге я использовал объекты запроса , что значительно упростило задачу.

...