简体   繁体   English

如何 select 并使用 NHibernate QueryOver 查询中的值对象集合

[英]How to select and consume a collection of value objects in an NHibernate QueryOver query

I have a simple model, consisting of a document that references one or more article using a reference object (this is because in the domain, we do not own the articles so we can only reference them).我有一个简单的 model,它包含一个使用参考 object 引用一篇或多篇文章的文档(这是因为在域中,我们不拥有这些文章,所以我们只能引用它们)。

I'm trying to write a query that lists the documents, printing the ID and a string consisting of a comma separated list of article numbers.我正在尝试编写一个列出文档的查询,打印 ID 和一个由逗号分隔的文章编号列表组成的字符串。 For example:例如:

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

My problem is with selecting the comma separated list.我的问题是选择逗号分隔的列表。

Here are the domain classes:以下是域类:

// 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; }
}

The article reference is a value object so it does not have an ID of its own.文章参考是一个值 object所以它没有自己的 ID。

This is the view model that represents an item in the result list:这是表示结果列表中的项目的视图 model:

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

And here's the query class I have come up with so far:这是我到目前为止提出的查询 class :

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; }
    }
}

As you can see, I can't express the .Where statement because there is no way of matching references to documents from a domain point of view.如您所见,我无法表达.Where语句,因为从域的角度来看,无法匹配对文档的引用。 The references are value objects and therefore don't have an ID.引用是值对象,因此没有 ID。

The question is: how do I fix the query to properly select the list of article numbers so I can use it in my string.Join statement to make the comma separated string?问题是:如何将查询正确地修复为string.Join文章编号列表,以便我可以在我的字符串中使用它。加入语句来制作逗号分隔的字符串?

I think you are taking the definition of value object too literally.我认为您对价值 object 的定义过于字面意思。 Assigning a surrogate identifier (identity column, Guid, etc.) to a value object does not make it any less of a value object.将代理标识符(标识列、Guid 等)分配给值 object 不会使其值小于 object。 It's a value object because its equality is based its values, not its identity.这是一个值 object因为它的相等性是基于它的值,而不是它的身份。 This does not require that a value object cannot have an identity, and in practice it almost always has to.这并不要求值 object 不能有标识,实际上它几乎总是必须的。

Your application obviously has to be able to link a Document to a set of ArticleReferences and the best way to accomplish that is by adding an ID to ArticleReference.您的应用程序显然必须能够将 Document 链接到一组 ArticleReference,而实现此目的的最佳方法是向 ArticleReference 添加一个 ID。

I managed to solve the problem.我设法解决了这个问题。 This is what I ended up with:这就是我最终的结果:

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();
    }
}

I couldn't use the alias-to-bean transformer anymore because it cannot handle collection properties.我不能再使用 alias-to-bean 转换器了,因为它不能处理集合属性。 That's why the solution has the GroupBy , it consolidates the rows, aggregating the article numbers into a string.这就是解决方案具有GroupBy的原因,它合并行,将文章编号聚合成一个字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM