recolha filtro NHibernate
-
07-07-2019 - |
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>
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