Подтвердить что ты не робот

Как получить отличный результат с помощью nHibernate и QueryOver API?

У меня есть этот метод репозитория

    public IList<Message> ListMessagesBy(string text, IList<Tag> tags, int pageIndex, out int count, out int pageSize)
    {
        pageSize = 10;
        var likeString = string.Format("%{0}%", text);
        var query = session.QueryOver<Message>()
            .Where(Restrictions.On<Message>(m => m.Text).IsLike(likeString) || 
            Restrictions.On<Message>(m => m.Fullname).IsLike(likeString));

        if (tags.Count > 0)
        {
            var tagIds = tags.Select(t => t.Id).ToList();
            query
                .JoinQueryOver<Tag>(m => m.Tags)
                .WhereRestrictionOn(t => t.Id).IsInG(tagIds);
        }            

        count = 0;
        if(pageIndex < 0)
        {
            count = query.ToRowCountQuery().FutureValue<int>().Value;
            pageIndex = 0;
        }
        return query.OrderBy(m => m.Created).Desc.Skip(pageIndex * pageSize).Take(pageSize).List();
    }

Вы предоставляете строку бесплатного текстового поиска и список тегов. Проблема в том, что если сообщение имеет более одного тега, оно отображается в дублированном времени. Я хочу получить отличный результат на основе объекта Message. Я просмотрел

Projections.Distinct

Но для этого требуется список свойств для отдельного вопроса. Это сообщение является моим корнем сущности, наиболее вероятно, способ получить это поведение без предоставления всех свойств объекта?

Заранее спасибо, Anders

4b9b3361

Ответ 1

Если вы используете API ICriteria, вам необходимо:

.SetResultTransformer(new DistinctEntityRootTransformer())

Если вы используете API QueryOver, вам необходимо:

.TransformUsing(Transformers.DistinctRootEntity)

Но будьте осторожны, все это происходит на стороне клиента, поэтому все повторяющиеся строки по-прежнему вытягиваются.

Ответ 2

Попробуйте что-то вроде этого

public IPagedList<Client> Find(int pageIndex, int pageSize)
{
    Client clientAlias = null;

    var query = Session.QueryOver<Client>(() => clientAlias)

        .Select(
            Projections.Distinct(
                Projections.ProjectionList()
                    .Add(Projections.Property<Client>(x => x.Id).As("Id"))
                    .Add(Projections.Property<Client>(x => x.Name).As("Name"))
                    .Add(Projections.Property<Client>(x => x.Surname).As("Surname"))
                    .Add(Projections.Property<Client>(x => x.GivenName).As("GivenName"))
                    .Add(Projections.Property<Client>(x => x.EmailAddress).As("EmailAddress"))
                    .Add(Projections.Property<Client>(x => x.MobilePhone).As("MobilePhone"))
            )
        )
        .TransformUsing(Transformers.AliasToBean<Client>())

        .OrderBy(() => clientAlias.Surname).Asc
        .ThenBy(() => clientAlias.GivenName).Asc;

    var count = query
        .ToRowCountQuery()
        .FutureValue<int>();

    return query
        .Take(pageSize)
        .Skip(Pagination.FirstResult(pageIndex, pageSize))
        .List<Client>()
        .ToPagedList(pageIndex, pageSize, count.Value);
}

Ответ 3

Вы можете использовать SelectList и GroupBy, например:

tags.SelectList(t => t.SelectGroup(x => x.Id))

Должен работать и производить тот же план запроса, что и отдельный.

Если вам нужно несколько элементов в группе, сделайте что-то вроде:

tags.SelectList(t => t.SelectGroup(x => x.Id)
                      .SelectGroup(x => x.Name)
               )

Ответ 4

Недавно я создал метод применения select select, основанный на сопоставленном типе объекта. Он применяет это к объекту IQueryOver (свойство класса). Метод также имеет доступ к конфигурации nhibernate. Вы можете добавить их как параметры метода. Нужна работа для производства, но метод отлично работает в dev, только использовал его для одного объекта.

Этот метод был создан, потому что я пытаюсь перечислить свои данные на уровне сервера, и отличный трансформатор результатов не будет работать.

После получения коллекции объектов (query.List()) вам может потребоваться перезагрузить объекты, чтобы заполнить один на многие дочерние объекты. Множество к одному сопоставлению будет проксировано для ленивых нагрузок.

 public void DistinctRootProjectionList<E>()
    {
        var classMapping = Context.Config.GetClassMapping(typeof(E));
        var propertyIterator = classMapping.UnjoinedPropertyIterator;
        List<IProjection> projections = new List<IProjection>();
        ProjectionList list = Projections.ProjectionList();

        list.Add(Projections.Property(classMapping.IdentifierProperty.Name), classMapping.IdentifierProperty.Name);

        foreach (var item in propertyIterator)
        {
            if (item.Value.IsSimpleValue || item.Value.Type.IsEntityType)
            {
                list.Add(Projections.Property(item.Name), item.Name);
            }
        }
        query.UnderlyingCriteria.SetProjection(Projections.Distinct(list));
        query.TransformUsing(Transformers.AliasToBean<E>());
    }

Код, который я использовал для загрузки одного из многих отношений... T - тип сущности.

for (int i = 0; i < resp.Data.Count; i++)
        {
            resp.Data[i] = session.Load<T>(GetInstanceIdValue(resp.Data[i]));
        }