Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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).

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. 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.

This is the view model that represents an item in the result list:

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:

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. The references are value objects and therefore don't have an 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?

like image 738
Sandor Drieënhuizen Avatar asked Nov 13 '22 18:11

Sandor Drieënhuizen


1 Answers

I think you are taking the definition of value object too literally. Assigning a surrogate identifier (identity column, Guid, etc.) to a value object does not make it any less of a value object. It's a value object because its equality is based its values, not its identity. This does not require that a value object cannot have an identity, and in practice it almost always has to.

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.

like image 51
Jamie Ide Avatar answered Dec 22 '22 07:12

Jamie Ide