NHIbernate学习之旅【六】——关系查询

  关系查询有一对多,多对多两种形式,说简单点就是多表查询。NHibernate实现起来比较简单。

  首先是建表:建构如下

  

  接下来是实体类:

  因为Customer对Order是1对多的关系,所以Customer.CS的实体类如下:

  Orders是个集合,这样可以通过用户ID查询到多个订单集合。

代码
    public class Customer
    {
        
public virtual int Id { getset; }
        
public virtual string FirstName { getset; }
        
public virtual string LastName { getset; }
        
//public virtual Name Name { get; set; }

        
public virtual int Version { getset; }
        
public virtual ISet<Order> Orders { getset; }

    }

 

  然后还要配置映射文件Customer.hbm.xml

  

代码
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
   assembly
="NHibernateSample.Domain"
   namespace
="NHibernateSample.Domain.Entities">

    
<class name ="Customer">
        
<id name="Id" column ="CustomerId">
            
<generator class ="native"/>
        
</id>
        
<version name="Version" column="Version" type="integer" unsaved-value="0"/>
        
<!--<component name="Name" class="NHibernateSample.Domain.Entities.Name,NHibernateSample.Domain">-->

            
<property name ="FirstName"/>
            
<property name ="LastName"/>
        
<!--</component>-->
            
<!--一对多关系:Customer有一个或多个Orders-->
    
<set name="Orders" table="[Order]" generic="true" inverse="true">
          
<key column="Customer" foreign-key="FK_CustomerOrders"/>
          
<one-to-many class="NHibernateSample.Domain.Entities.Order,NHibernateSample.Domain"/>
    
</set>

    
</class>
</hibernate-mapping>

 

一下引用李永京老师的:

NHibernate支持/定义的几种类型的集合:

Bag:对象集合,每个元素可以重复。例如{1,2,2,6,0,0},在.Net中相当于IList或者IList<T>实现。

Set:对象集合,每个元素必须唯一。例如{1,2,5,6},在.Net中相当于ISet或者ISet<T>实现,Iesi.Collections.dll程序集提供ISet集合。

List:整数索引对象集合,每个元素可以重复。例如{{1,"YJingLee"},{2,"CnBlogs"},{3,"LiYongJing"}},在.Net中相当于ArraryList或者List<T>实现。

Map:键值对集合。例如{{"YJingLee",5},{"CnBlogs",7},{"LiYongJing",6}},在.Net中相当于HashTable或者IDictionary<Tkey,TValue>实现。

实际上,我们大多数情况下使用Set集合类型,因为这个类型和关系型数据库模型比较接近。

 

  • Inverse="false"(默认):父实体负责维护关联关系
  • Inverse="true":子实体负责维护关联关系
  •  

    foreign-key:可以随便起个名字。

    one-to-many代表一对多。

    这样我们就完成了父类的配置。

     

      接下来是子类的Order.cs

      

    代码
        public class Order
        {
            
    public virtual int OrderId { getset; }
            
    public virtual DateTime OrderDate { getset; }
            
    //多对一关系:Orders属于一个Customer
            public virtual Customer Customer { getset; }
            
    //多对多关系:Order有多个Products
            public virtual IList<Product> Products { getset; }

        }

     

      因为一个订单可以有多个产品,一个产品又可以又多个订单,所以是多对多的关系,因此对于用户就是Customer,对于产品就是一个集合。

      接下来是Order.hbm.xml

      

    代码
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
       assembly
    ="NHibernateSample.Domain"
       namespace
    ="NHibernateSample.Domain.Entities">

        
    <class name="Order"  table="[Order]">
            
    <id name="OrderId" column="OrderId" type="Int32" unsaved-value="0">
                
    <generator class="native" />
            
    </id>
            
    <property name="OrderDate" column="OrderDate" type="DateTime"
                      not-null
    ="true" />
            
    <!--多对一关系:Orders属于一个Customer-->
            
    <many-to-one name="Customer" column="Customer" not-null="true"
                         class
    ="NHibernateSample.Domain.Entities.Customer,NHibernateSample.Domain"
                         foreign-key
    ="FK_CustomerOrders" />
            
    <!--多对多关系:Order有多个Products-->
            
    <bag name="Products" generic="true" table="OrderProduct">
                
    <key column="[Order]" foreign-key="FK_OrderProducts"/>
                
    <many-to-many column="Product"
                           class 
    ="NHibernateSample.Domain.Entities.Product,NHibernateSample.Domain"
                           foreign-key
    ="FK_ProductOrders"/>
            
    </bag>

        
    </class>
    </hibernate-mapping>

      这里的name的值任意,但column父子类必须一致。

      还有一个Product表:

      Product.cs

    代码
        public class Product
        {
            
    public virtual int ProductId { getset; }
            
    public virtual string Name { getset; }
            
    public virtual float Cost { getset; }
            
    //多对多关系:Product属于多个Orders
            public virtual IList<Order> Orders { getset; }
        }

     

    Product.hbm.XML 别忘了嵌入资源

    代码
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                       assembly
    ="NHibernateSample.Domain" namespace="NHibernateSample.Domain.Entities">
        
    <class name="NHibernateSample.Domain.Entities.Product,NHibernateSample.Domain" table="Product">

            
    <id name="ProductId" column ="ProductId" type="Int32" unsaved-value="0">
                
    <generator class="native"/>
            
    </id>
            
    <property name="Name" column="Name" type="string" not-null="true" length="50"/>
            
    <property name="Cost" column="Cost" type="float" not-null="true"/>
            
    <!--多对多关系:Product属于多个Orders-->
            
    <bag name="Orders" generic="true" table="OrderProduct">
                
    <key column="Product" foreign-key="FK_ProductOrders"/>
                
    <many-to-many column="`Order`"
                            class
    ="NHibernateSample.Domain.Entities.Order,NHibernateSample.Domain"
                            foreign-key
    ="FK_OrderProducts"/>
            
    </bag>
        
    </class>
    </hibernate-mapping>

     

      关于OrderProduct表我们不用写实体类和映射文件,只要在Order和Product的映射文件中进行配置就行,大家可能已经注意到了就是Order和Product的bag节点中的table=“OrderProduct” ,下面在配置关联的字段,即<KEY>节点。这样在查询的时候Nhibernate会自动帮你关联的。

     

    好了 到此就配置完了,可以开始使用了

      首先是一对多的三种查询

      以下查询出现:在关键字ORDER附近又语法错误 的话 那是因为order是关键字,要用[]括起来,在ORDER映射文件中的CLASS节点中加Table="[Order]"。

    代码
                return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}" +
                
    " inner join [Order] o on o.Customer={customer}.CustomerId where o.Orderid= :orderid")
                    .AddEntity(
    "customer"typeof(Customer))
                    .SetInt32(
    "orderid", orderid)
                    .List
    <Customer>();

     

     

    代码
    public IList<Customer> UseHQL_GetCustomersWithOrders(DateTime orderDate)
    {
        
    return _session.CreateQuery("select distinct c from Customer c inner join c.Orders o  where o.OrderDate > :orderDate")
            .SetDateTime(
    "orderDate", orderDate)
            .List
    <Customer>();
    }

     

     

     

    代码
    public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
    {
        
    return _session.CreateCriteria(typeof(Customer))
            .CreateCriteria(
    "Orders")
            .Add(Restrictions.Gt(
    "OrderDate", orderDate))
            .List
    <Customer>();
    }

     

     

    再就是多对多的查询,和一对多没多大区别:

     

    代码
            public IList<Customer> UseSQL_GetCustomersWithOrdersHavingProduct(int orderid)
            {
                
    return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}" +
                
    " inner join [Order] o on o.Customer={customer}.CustomerId" +
                
    " inner join OrderProduct op on o.OrderId=op.[Order]" +
                
    " inner join Product p on op.Product=p.ProductId where p.ProductId= :OrderId")
                    .AddEntity(
    "customer"typeof(Customer))
                    .SetInt32(
    "OrderId", orderid)
                    .List
    <Customer>();
            }

     

     

     

    代码
    public IList<Customer> UseHQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
    {
        
    return _session.CreateQuery("select distinct c from Customer c ,"
            
    + " c.Orders.elements o where o.OrderDate > :orderDate")
            .SetDateTime(
    "orderDate", orderDate)
            .List
    <Customer>();
    }

     

     

    代码
            public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct(string strname)
            {
                
    return _session.CreateCriteria(typeof(Customer))
                    .CreateCriteria(
    "Orders")
                    .CreateCriteria(
    "Products")
                    .Add(Restrictions.Eq(
    "Name", strname))
                    .List
    <Customer>();
            }

    以上查询都经过测试,都是通过一张表的查询返回另一种表的数据。

     

    posted on 2010-05-14 13:33  neekey  阅读(612)  评论(0)    收藏  举报

    导航