如何使用集合属性对一对多表执行联接查询?

时间:2011-02-02 09:29:11

标签: nhibernate join

我有两张桌子; t_users(user_id pk,user_name,password)和t_transactions(trans_id pk,user_id fk,item_name,amount)。 我们可以看到,t_users是父表,而t_transactions是子表,所以我为它们创建了两个类:

public class User
    {       
        public int ID {get; set;}
        public string Name {get; set;}
        public string Password {get; set;}
        public IList<Transaction> Transactions {get; set;}
        public IList<Group> Groups {get; set;}
    }

public class Transaction
    {
        public Transaction()
        {
        }

        public int ID {get; set;}
        public int UserID {get; set;}
        public string ItemName {get; set;}
        public decimal Amount {get; set;}
        public User User {get; set;}
    }

这是我的映射:

用户

<class name="User" table="t_users" lazy="false">
        <id name="ID" column="user_id" />
        <property name="Name" column="user_name"/>
        <property name="Password" column="password" />
        <bag name="Transactions" lazy="false" cascade="all">
            <key column="user_id" />            
            <one-to-many class="Transaction" />
        </bag>      
        <bag name="Groups" table="t_users_groups" lazy="false" cascade="all" inverse="true">
            <key column="user_id" />
            <many-to-many column="group_id" class="Group" />
        </bag>      
    </class>

交易:

<class name="Transaction" table="t_transactions" lazy="false">
        <id name="ID" column="trans_id" />
        <property name="UserID" column="user_id"/>
        <property name="ItemName" column="item_name" />
        <property name="Amount" column="amount" />
        <many-to-one name="User" column="user_id" class="User" />
    </class>

我如何调用此查询

SELECT u.user_id, u.user_name, u.password, t.trans_id, t.user_id, t.item_name, t.amount
      FROM t_users u INNER JOIN t_transactions t on u.user_id = t.user_id
      WHERE amount <= :limit

哪个应该返回唯一的父对象(u),并且重复的子表(t)应该部分/放置在类User的属性Transactions中?

谢谢!

1 个答案:

答案 0 :(得分:1)

你做错了,因为你不能拥有域实体的“一半”。你想要的是交易,所以你应该查询交易。

在hql中:

from Transaction t 
where t.Amount <= :limit

您是否希望获取用户属性?

from Transaction t
join fetch t.User
where t.Amount <= :limit

然后您可以创建命名查询,也可以执行

session.CreateQuery(query).List<Transaction>();

如果您需要类似域对象的对象结构,则可以执行以下操作:

public class UserWithTransactionsViewModel
{
  public string UserName {get; set; }
  public IEnumerable<TransactionViewModel> Transactions {get; set;}
}

您可以按如下方式在内存中创建投影:

var vms = session.CreateQuery(query)
       .List<Transaction>()
       .GroupBy(t => t.User)
       .Select( g => new UserWithTransactionViewModel
                        { 
                          UserName = g.Key.Name
                          Transactions = g.Select(t => new TransactionViewModel(....)).ToArray()
                        });

另一个方法是查询具有大于...的一个事务的用户,然后在投影到viewmodel或dto时过滤内存中的事务。但我不喜欢这个,因为你有两个不同位置的过滤逻辑,它的性能更差,因为你甚至可以获得内存,甚至是你不想要的事务。

我的一般建议是,当您使用ORM时,您的实例应该在内存中保持一致始终

PS:您不需要Transaction类中的UserId属性。这是一个设计错误。