Pergunta

Usando NHibernate que eu quero para filtrar uma coleção em uma classe para conter apenas um subconjunto de objetos possíveis. Abaixo eu estou incluindo uma tabela de dados de amostra para ajudar a explicar. Eu posso não encontrar nenhuma maneira de fazer isso usando NHibernate.

Table: DataObject

DataObjectId (PK) / Nome / CurrentVersion

11          "data.txt"      2
12          "info.txt"      3

Table: DataObjectVersion

Id / Comment / VersionNumber / DataObjectId (FK)

31   "Genesis"         1          11     <= Ignore this object
32   "Changed data"    2          11     <= Get this object
34   "Genesis"         1          12     <= Ignore this object   
35   "Changed info"    2          12     <= Ignore this object
36   "Added info"      3          12     <= Get this object

Eu quero juntar-se em uma chave não-estrangeira DataObject.CurrentVersion = DataObjectVersion.VersionNumber para cada DataObject em um comando.

Aqui estão as classes e arquivos de mapeamento:

public class DataObject
{
  public virtual int DataObjectId { get; set; }
  public virtual string Name { get; set; }
  public virtual int CurrentVersionNumber { get; set; }
  public virtual IList<DataObjectVersion> Versions { get; set; }
}

<class name="DataObject" table="DataObject" lazy="false">
    <id name="DataObjectId" column="DataObjectId" type="int">
      <generator class="assigned" />
    </id>
    <property name="Name" column="Name" type="String(512)" />
    <property name="CurrentVersionNumber" column="CurrentVersionNumber" type="int" />
    <bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" >
        <key column="DataObjectId" />
        <one-to-many class="DataObjectVersion" />
    </bag>
</class>

public class DataObjectVersion
{
    public virtual int DataObjectVersionId { get; set; }
    public virtual string Comment { get; set; }
    public virtual int VersionNumber { get; set; }
    public virtual int DataObjectId { get; set; }
}

<class name="DataObjectVersion" table="DataObjectVersion" lazy="false">
    <id name="Id" column="DataObjectVersionId" type="int">
      <generator class="assigned" />
    </id>
    <property name="Comment" column="Comment" type="String(512)" />
    <property name="VersionNumber" column="VersionNumber" type="int" />
    <property name="DataObjectId" column="DataObjectId" type="int" />
</class>  
Foi útil?

Solução

Se você quiser filtrar a coleção sob demanda, usando um filtro é uma opção válida. Você precisaria declarar o filtro em ambas as classes de versão e no elemento de saco e aplicar o filtro a partir do método NHibernateSession.EnableFilter

Se você quer sempre buscar uma única versão no saco, em seguida, implementar um 'onde' no mapeamento do saco:

<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" where="CurrentVersionNumber = Versions.VersionNumber" >
    <key column="DataObjectId" />
    <one-to-many class="DataObjectVersion" />
</bag>

Note que no 'onde' você escreve SQL adequada não HQL e, como tal, o SQL apropriado eu escrevo acima, provavelmente, tem de ser alterado para refletir o esquema

Além disso, se um único objecto é para ser ajuste forçado até um saco e o segundo IList pode ser um exagero. Aplicando uma propriedade fórmula e um objeto DataObjectVersion na classe pode ser mais apropriado

na classe DataObject substituir o IList com

public virtual DataObjectVersion Version { get; set; }

e no mapeamento substituir o 'saco' com algo nas linhas de

<property name="Version" type="DataObjectVersion" update="false" insert="false" formula="(select v.DataObjectVersionId, v.Comments, v.VersionNumber, v.DataObjectId from DataObjectVersion v where v.VersionNumber  = CurrentVersionNumber)" />

novamente apenas SQL adequada é permitido

i usei propriedades computadas com tipos de dados nativos (datetime, corda etc) e buscar uma entidade pode (ou não pode) precisa de algo mais ou diferente

Por último, mas não menos importante, você pode aplicar um filtro na coleção após você tem buscado o DataObject objeto principal, criando um filtro na coleção

IList<DataObjectVersion>  fVersion = 
    NHibernateSession.CreateFilter(do.Versions, "where VersionNumber = :ver")
        .SetParameter("ver", do.CurrentVersionNumber)
        .List<DataObjectVersion>();

onde a coleção do.Versions não é inicializado, apenas os resultados buscados na coleção fVersion separado e este é um segundo SELECT depois de já ter feito a ida e volta para o db para o DataObject buscar.

Outras dicas

Presumivelmente seus incrementos VersionNumber como o usuário altera os dados e você está tentando obter o mais recente. Se você considerar o VersionNumber como um campo "Idade" em vez (ou seja, em que 0 é a versão mais recente / mais novo, 1 é o próximo mais antigo e assim por diante), então seus problemas torna-se como obter todas as entidades com uma idade de 0. Esta lata ser feito usando um filtro: http://nhibernate.info/doc/ nh / en / index.html # objectstate-filtra

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top