Question

I have two tables (Orders, Transactions) and a TransactionsOrders lookup table that just retains an OrderId and TransactionsId columns.

There can be multiple transactions for an order if a transaction failed (n) times. And the Order object doesn't have any knowledge of the transactions.

I believe I will need to use projections as I will need to return all the order properties as well as two properties from the Transactions table (Amount and TransactionDate) if a successful transaction record exists for that order. Below is the SQL that will generate the correct output.

   SELECT o.*, ct.TransactionDate, ct.Amount from Orders o
   LEFT OUTER JOIN 
     (SELECT * FROM CreditTransactionsOrders cto
          INNER JOIN CreditTransactions ct 
      ON ct.Id = cto.CreditTransactionId
      WHERE ct.Successful = 1) as ct 
   ON o.Id = ct.OrderId

I have attempted to try creating this QueryOver and projecting the properties I need from the Order object and Transaction object but can't convert this SQL query properly.

The end results is that I need to return ALL orders, and I need to return the Amount and Date from the Transaction object IF a successful one exists for that Order. I am not really sure if I have to use aliases, but so far all my attempts have been unsuccessful.

Was it helpful?

Solution

First you have to rewrite your SQL to more NHibernate friendly state:

SELECT o.*, ct.TransactionDate, ct.Amount from Orders o
  LEFT OUTER JOIN CreditTransactionsOrders cto 
    ON o.Id = cto.OrderId
  LEFT OUTER JOIN CreditTransactions ct 
    ON ct.Id = cto.CreditTransactionId AND ct.Successful = 1

This SQL will produce the same results as your original query.

In NHibernate additional criteria for join could be translated as with statement.

So you could use overload accepting withClause argument. So, assuming you have Orders and CreditTransactions mapped as many-to-many. You should get following QueryOver.

Order o = null;
CreditTransaction ct = null;

var orders = session.QueryOver(() => o)
    .Left.JoinAlias(x => x.Transactions, () => ct, () => ct.Successful == 1)
    .List<Order>();

UPDATE

As you have no reference from Order to Transaction, you should revert the join, so you could use right join to achieve this.

Order o = null;
CreditTransaction ct = null;

var orders = session.QueryOver(() => ct)
    .Right.JoinAlias(x => x.Orders, () => o, () => ct.Successful == 1)
    .Select(
        x => x.TransactionDate,
        x => x.Amount,
        x => o.Id // other Order fields
    ).TransformUsing(Transformers.AliasToBean<TransactionsDto>())
    .List<TransactionsDto>();

TransactionsDto class should contain all selected fields.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top