2011-08-14 14 views
5

Tengo un modelo simple, que consiste en un documento que hace referencia a uno o más artículo utilizando un objeto de referencia (esto es debido a que en el dominio, que no poseen los artículos así que solo podemos hacer referencia a ellos).Cómo seleccionar y consumir una colección de objetos de valor en una consulta NHibernate QueryOver

estoy tratando de escribir una consulta que lista los documentos, imprimir la ID y una cadena que consiste en una lista separada por comas de los números de artículo separado. Por ejemplo:

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

Mi problema es con la selección de la lista separada por comas.

Estas son las clases de dominio:

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

La referencia del artículo es un objeto de valor por lo que no tiene una identificación propia.

Este es el modelo de vista que representa un elemento de la lista de resultados:

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

y aquí está la clase de consulta que he encontrado hasta el momento:

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

Como se puede ver, No puedo expresar la declaración .Where porque no hay forma de hacer coincidir las referencias a los documentos desde el punto de vista de un dominio. Las referencias son objetos de valor y, por lo tanto, no tienen una ID.

La pregunta es: ¿Cómo puedo solucionar la consulta para seleccionar correctamente la lista de números de artículo para que pueda usarlo en mi declaración string.Join para hacer la cadena separada por comas?

+0

has necesitado añadir public int? DocumentId {get; set;} a ArticleReference? ps no son las propiedades que se supone que son virtuales en nhibernate –

+0

Tienes razón sobre los virtuales, actualicé mi pregunta. Me había olvidado de ellos al escribir el código conceptual (el código real es demasiado molesto debido a su tamaño). En cuanto a agregar DocumentId a ArticleReference: eso desafiaría toda la idea de objetos de valor, convirtiéndolo efectivamente en una entidad. –

+0

true - pero debido a problemas como estos, suelo tener un modelo de dominio separado para mi modelo de aplicación, así que agrego funnies como agregar una propiedad parentid a una entidad secundaria. –

Respuesta

0

me las arreglé para resolver el problema. Esto es lo que terminó con:

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

que no podía usar el transformador-alias-frijol a más porque no puede manejar propiedades de la colección. Es por eso que la solución tiene el GroupBy, consolida las filas, agregando los números de los artículos en una cadena.

1

creo que usted está tomando la definición de objeto de valor demasiado literalmente. Asignar un identificador sustituto (columna de identidad, Guid, etc.) a un objeto de valor no lo convierte en un objeto menos de valor. Es un value object porque su igualdad se basa en sus valores, no en su identidad. Esto no requiere que un objeto de valor no pueda tener una identidad, y en la práctica casi siempre tiene que hacerlo.

Su aplicación, obviamente, tiene que ser capaz de vincular un documento a un conjunto de ArticleReferences y la mejor manera de lograr esto es mediante la adición de una identificación para ArticleReference.

+1

En cuanto a dar una identidad a un objeto de valor, solo puedo pensar en razones válidas que se refieren a la compensación de limitaciones técnicas en otros lugares, como en la capa de persistencia. Desde el punto de vista de un dominio, una identidad de objeto de valor es superflua (a menos que el dominio mismo sea defectuoso) porque el objeto de valor ES la identidad. Entiendo de dónde vienes, pero dado que he logrado encontrar una solución (que publicaré aquí pronto) para este problema, tampoco parece necesario agregar una identidad, así que me quedaré con mi punto de vista hasta nuevo aviso :) –

Cuestiones relacionadas