• [NHibernate]一对多关系(关联查询)


    目录

    写在前面

    文档与系列文章

    一对多查询

    总结

    写在前面

    上篇文章介绍了nhibernate的一对多关系如何配置,以及级联删除,级联添加数据的内容。这篇文章我们将学习nhibernate中的一对多关系的关联查询。前面文章中也介绍的nhibernate的查询:HQL,条件查询,原生SQL查询。

    文档与系列文章

    [Nhibernate]体系结构

    [NHibernate]ISessionFactory配置

    [NHibernate]持久化类(Persistent Classes)

    [NHibernate]O/R Mapping基础

    [NHibernate]集合类(Collections)映射 

    [NHibernate]关联映射

    [NHibernate]Parent/Child

    [NHibernate]缓存(NHibernate.Caches)

    [NHibernate]NHibernate.Tool.hbm2net

    [NHibernate]Nullables

    [NHibernate]Nhibernate如何映射sqlserver中image字段

    [NHibernate]基本配置与测试 

    [NHibernate]HQL查询 

    [NHibernate]条件查询Criteria Query

    [NHibernate]增删改操作

    [NHibernate]事务

    [NHibernate]并发控制

    [NHibernate]组件之依赖对象

    [NHibernate]一对多关系(级联删除,级联添加)

    一对多查询

    原生sql关联查询

    查询某一个客户的信息,以及该客户所下的订单信息

     1         /// <summary>
     2         /// 查询某客户信息与该客户的订单信息
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public IList<Customer> GetCustomerOrders(Guid customerID)
     7         {
     8             //获得ISession实例
     9             ISession session = NHibernateHelper.GetSession();
    10             //实例化IQuery接口;使用ISession.CreateSQLQuery()方法,传递的参数是SQL查询语句
    11             return session.CreateSQLQuery("select distinct tb_customer.*,tb_order.* from tb_customer "
    12                 + "inner join tb_order on tb_customer.customerid=tb_order.customerid where tb_customer.customerid=:id")
    13                 .AddEntity("Customer", typeof(Customer))
    14                 .SetGuid("id", customerID)
    15                 .List<Customer>();
    16         }

    注意,此时使用的是真正的sql,里面使用的是数据表,这点与hql不同(hql中使用的是面向对象的概念,使用的是数据表映射的实体类对象)。

     1         /// <summary>
     2         /// 按客户id查询客户信息及订单信息
     3         /// </summary>
     4         /// <param name="sender"></param>
     5         /// <param name="e"></param>
     6         protected void btnSearchByID_Click(object sender, EventArgs e)
     7         {
     8             Business.CustomerBusiness customerBusiness = new Business.CustomerBusiness();
     9             this.rptCustomerList.DataSource = customerBusiness.GetCustomerOrders(new Guid("B0720295-9541-40B3-9994-610066224DB8"));
    10             this.rptCustomerList.DataBind();
    11         }

     生成的sql语句,因为使用的inner join ,测试的数据为一个客户对应的订单有2个,所以查询出来的数据有2条。

    HQL关联查询

    使用HQL查询,某一个客户的信息,以及该客户所下的订单信息

     1         /// <summary>
     2         /// HQL查询某客户信息与该客户的订单信息
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public IList<Customer> GetCustomerOrdersByHQL(Guid customerID)
     7         {
     8             //获得ISession实例
     9             ISession session = NHibernateHelper.GetSession();
    10             return session.CreateQuery("select c from Customer c inner join c.Orders  where c.CustomerID=:id")
    11                 .SetGuid("id", customerID)
    12                 .List<Customer>();
    13         }

    通过观察,可以发现inner join 后面的Orders为实体Customer的一个属性,这种面向对象的方式更符合咱们的开发习惯。

    生成的sql语句为

    Criteria API条件查询

    使用Criteria API条件查询,某一个客户的信息,以及该客户所下的订单信息

    使用CreateCriteria()在关联之间导航,很容易地在实体之间指定约束。这里第二个CreateCriteria()返回一个ICriteria的新实例,并指向Orders实体的元素。在查询中子对象使用子CreateCriteria语句,这是因为实体之间的关联我们在映射文件中已经定义好了。

    还有一种方法使用CreateAlias()不会创建ICriteria的新实例。

     1         /// <summary>
     2         /// Criteria API查询某客户信息与该客户的订单信息
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public IList<Customer> GetCustomerOrdersByCriteria(Guid customerID)
     7         {
     8             //获得ISession实例
     9             ISession session = NHibernateHelper.GetSession();
    10             return session.CreateCriteria(typeof(Customer))
    11                 .CreateCriteria("Orders")
    12                 .Add(Restrictions.Eq("Customer.CustomerID", customerID))
    13                 .List<Customer>();
    14         }

    这个地方需要注意因为在Order和Customer实体中都有CustomerID属性,需要指明是哪个CustomerID。
    生成的sql

    这种方式得到的结果可能重复,可通过如下方式进行预过滤

    预过滤

    使用ICriteria接口的SetResultTransformer(IResultTransformer resultTransformer)方法返回满足特定条件的Customer。上面例子中使用条件查询,观察其生成的SQL语句并没有distinct,这时可以使用NHibernate.Transform命名空间中的方法或者使用NHibernate提供的NHibernate.CriteriaUtil.RootEntity、NHibernate.CriteriaUtil.DistinctRootEntity、NHibernate.CriteriaUtil.AliasToEntityMap静态方法实现预过滤的作用。那么上面的查询应该修改为:

     1         /// <summary>
     2         /// Criteria API查询某客户信息与该客户的订单信息
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public IList<Customer> GetCustomerOrdersByCriteria(Guid customerID)
     7         {
     8             //获得ISession实例
     9             ISession session = NHibernateHelper.GetSession();
    10             return session.CreateCriteria(typeof(Customer))
    11                 .CreateCriteria("Orders")
    12                 .Add(Restrictions.Eq("Customer.CustomerID", customerID))
    13                 //预过滤重复的结果
    14                 .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
    15                 //或者.SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity)
    16                 .List<Customer>();
    17         }

    生成的sql语句

    没预过滤的

    使用预过滤的

    此时查询的Order为一条。通过对比你会发现他们生成的sql语句一样,真正实现过滤的应该是在内存中做的。

    投影

    调用SetProjection()方法可以实现应用投影到一个查询中。NHibernate.Criterion.Projections是Projection的实例工厂,Projections提供了非常多的方法。

     1         /// <summary>
     2         /// 投影查询某客户信息与该客户的订单信息
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public IList<Customer> GetCustomerOrdersByProjection(Guid customerID)
     7         {
     8             //获得ISession实例
     9             ISession session = NHibernateHelper.GetSession();
    10             IList<Guid> ids = session.CreateCriteria(typeof(Customer))
    11                 .SetProjection(Projections.Distinct(
    12                 Projections.ProjectionList()
    13                 .Add(Projections.Property("CustomerID"))
    14                 )
    15                 )
    16                 .CreateCriteria("Orders")
    17         .Add(Restrictions.Eq("Customer.CustomerID", customerID))
    18         .List<Guid>();
    19             return session.CreateCriteria(typeof(Customer))
    20        .Add(Restrictions.In("CustomerID", ids.ToArray<Guid>()))
    21        .List<Customer>();
    22         }

    我们可以添加若干的投影到投影列表中,例如这个例子我添加一个CustomerId属性值到投影列表中,这个列表中的所有属性值都设置了Distinct投影,第一句返回订单的客户CustomerId,第二句根据返回的CustomerId查询顾客列表。达到上面的目的。这时发现其生成的SQL语句中有distinct。我们使用投影可以很容易的组合我们需要的各种方法。

    生成的sql语句

    总结

    这里介绍了处理一对多关系的关联查询的方式,希望对你有所帮助。

    参考地址:http://www.cnblogs.com/lyj/archive/2008/10/26/1319889.html

  • 相关阅读:
    lodash-es 最小化引入
    shortid id生成器
    结构体声明的方式 及类namespace的前置声明
    结构体中使用 箭头 与 点 的区别
    进入Docker容器的几种方式
    协议分析处理工具ProtoBuf
    PubSub ——“发布/订阅”模式
    在Windows/linux下进行gdb调试
    C++中的域作用符::的作用
    C++ 中常用关键字及其用法
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4070935.html
Copyright © 2020-2023  润新知