Как выбрать и использовать коллекцию объектов-значений в запросе NHibernate QueryOver - PullRequest
5 голосов
/ 15 августа 2011

У меня есть простая модель, состоящая из документа, который ссылается на одну или несколько статей с использованием ссылочного объекта (это потому, что в домене мы не являемся владельцами статей, поэтому можем ссылаться только на них).

Я пытаюсь написать запрос со списком документов, распечатать идентификатор и строку, состоящую из разделенного запятыми списка номеров статей. Например:

ID ARTICLES
------------------
1  ACC, PE2,
2  ER0, AQ3, FEE
3  PE2

Моя проблема с выбором списка через запятую.

Вот классы доменов:

// The Entity class has an Id property.
public class Document : Entity
{
    public virtual IEnumerable<ArticleReference> ArticleReferences { get; set; }
    public virtual DateTime ReceiveDate { get; set; }
}

// The ValueObject does not have an Id property ofcourse.
public class ArticleReference : ValueObject
{
    public virtual string ArticleNumber { get; set; }
    public virtual string ArticleName { get; set; }
}

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

Это модель представления, представляющая элемент в списке результатов:

public class DocumentListItemModel
{
    public int Id { get; set; }
    public string ArticleNumbers { get; set; }
    public string ReceiveDate { get; set; }
}

А вот класс запросов, который я создал до сих пор:

public class DocumentQuery
{
    public IList<DocumentListItemModel> ExecuteQuery()
    {
        IntermediateModel model = null;
        ArticleReference articleReferenceAlias = null;

        return Session
            .QueryOver<Document>()
            .JoinAlias(n => n.ArticleReferences, () => articleReferenceAlias);
            .SelectSubQuery(
                QueryOver.Of<ArticleReference>(() => articleReferenceAlias)
                    // There is no way of matching references to documents from a domain
                    // point of view since the references are value objects and
                    // therefore don't have an ID.
                    .Where(n => ...)
                    .Select(q => articleReferenceAlias.Number))
                .WithAlias(() => model.ArticleNumbers)
            .TransformUsing(Transformers.AliasToBean<IntermediateModel>());
            .Future<IntermediateModel>()
            .ToList()
            .Select(n =>
                new DocumentListItemModel()
                {
                    Id = n.Id,
                    ArticleNumbers = string.Join(", ", n.ArticleNumbers.OrderBy(p => p)),
                    ReceiveDate = n.ReceiveDate.ToString("d", CultureInfo.CurrentCulture)
                })
            .ToList();
    }

    private class IntermediateModel
    {
        public int Id { get; set; }
        public IEnumerable<string> ArticleNumbers { get; set; }
        public DateTime ReceiveDate { get; set; }
    }
}

Как видите, я не могу выразить оператор .Where, потому что нет способа сопоставления ссылок на документы с точки зрения домена. Ссылки являются объектами значений и поэтому не имеют идентификатора.

Вопрос в следующем: как исправить запрос, чтобы правильно выбрать список номеров статей, чтобы я мог использовать его в своем операторе string.Join для создания строки, разделенной запятыми?

Ответы [ 2 ]

1 голос
/ 03 сентября 2011

Я думаю, вы слишком буквально понимаете определение объекта значения. Присвоение суррогатного идентификатора (столбец идентификаторов, Guid и т. Д.) Объекту значения не делает его менее значимым объектом. Это объект значения , потому что его равенство основано на его значениях, а не на его идентичности. Это не требует, чтобы объект значения не мог иметь идентичность, и на практике это почти всегда должно.

Очевидно, что ваше приложение должно иметь возможность связать документ с набором ArticleReferences, и лучший способ сделать это - добавить идентификатор в ArticleReference.

0 голосов
/ 07 сентября 2011

Мне удалось решить проблему. Вот чем я закончил:

public IList<DocumentListItemModel> ExecuteQuery()
{
    ArticleReference articleReferenceAlias = null;

    return Session
        .QueryOver<Document>()
        .JoinAlias(n => n.ArticleReferences, () => articleReferenceAlias,
            JoinType.LeftOuterJoin)
        .SelectList(list => list
            .Select(n => n.Id)
            .Select(n => articleReferenceAlias.Number))
        .List<object[]>()
        .Select(x => new
        {
            Id = (int)x[0],
            ArticleNumber = (string)x[1]
        })
        .GroupBy(n => n.Id).Select(n =>
        {
            return new DocumentListItemModel
            {
                Id = n.First().Id,
                ArticleNumbers = string.Join(", ", n.Select(p => p.ArticleNumber))
            };
        }).ToList();
    }
}

Я больше не мог использовать преобразователь псевдонима в bean-компонент, потому что он не может обрабатывать свойства коллекции. Вот почему решение имеет GroupBy, оно объединяет строки, объединяя номера статей в строку.

...