To get the result you want when writing a query in SQL it would be necessary to write something along the lines of:
SELECT Client_Id, Client_Name, Manufacturer_Id, Manufacturer_Name
FROM
(
SELECT Client.Id as Client_Id, Client.Name as Client_Name,
Manufacturer.Id as Manufacturer_Id, Manufacturer.Name as Manufacturer_Name
FROM ClientTax
INNER JOIN Client on Client.Id = ClientTax.Client_Id
INNER JOIN Manufacturer on Manufacturer.Id = Manufacturer.Manufacturer_id
UNION
SELECT Client.Id, Client.Name, Manufacturer.Id, Manufacturer.Name
FROM InstructionTemplate
INNER JOIN Client on Client.Id = InstructionTemplate.Client_Id
INNER JOIN Manufacturer on Manufacturer.Id = InstructionTemplate.Manufacturer_id
) a
GROUP BY Client_Id, Client_Name, Manufacturer_Id, Manufacturer_Name;
Unfortunately converting such a query to one of NHibernate's query APIs is not possible because NHibernate does not support the UNION statement*. See this question and the feature request NH-2710 in NHibernate's bug tracker.
*Except when using union-subclass
. See the docs for further details
The only options I can see are
Perform an SQL Query and map this to a DTO
public class InstructionTemplateInfo { public int Client_Id { get; set; } public string Client_Name { get; set; } public int Manufacturer_Id { get; set; } public string Manufacturer_Name { get; set; } }
then
var result = session .CreateSQLQuery(theSQLQueryString) .SetResultTransformer(Transformers.AliasToBean<InstructionTemplateInfo>()) .List<InstructionTemplateInfo>();
Create a view in the database and map this like a normal entity.
If the DBMS supports multiple results sets, like SQL Server, you could write two queries but mark them both as
Future
and then merge the two results set in code, i.e.var resultSet1 = Session.QueryOver<ClientTaxEntity>(() => taxEntity) .JoinAlias(x => x.Client, () => client) .JoinAlias(x => x.Manufacturers, () => manufacturer) .SelectList(builder => builder .SelectGroup((() => client.Name).WithAlias(() => info.ClientName) .SelectGroup((() => client.Id).WithAlias(() => info.ClientId) .SelectGroup((() => manufacturer.Name).WithAlias(() => info.ManufacturerName) .SelectGroup((() => manufacturer.Id).WithAlias(() => info.ManufacturerId) .TransformUsing(Transformers.AliasToBean<InstructionTemplateInfo>()) .Future<InstructionTemplateInfo>; var resultSet2 = Session.QueryOver<InstructionTemplate>(() => taxEntity) .JoinAlias(x => x.Client, () => client) .JoinAlias(x => x.Manufacturers, () => manufacturer) .SelectList(builder => builder .SelectGroup((() => client.Name).WithAlias(() => info.ClientName) .SelectGroup((() => client.Id).WithAlias(() => info.ClientId) .SelectGroup((() => manufacturer.Name).WithAlias(() => info.ManufacturerName) .SelectGroup((() => manufacturer.Id).WithAlias(() => info.ManufacturerId) .TransformUsing(Transformers.AliasToBean<InstructionTemplateInfo>()) .Future<InstructionTemplateInfo>; var result = resultSet1.Concat(resultSet2 ) .GroupBy(x=>x.ClientId+"|"+x.ManufacturerId) .Select(x=>x.First());
The advantage of this approach is that the DBMS will only be hit once. See Ayende's blog post for further details about this feature.