如何为地图定义hibernate映射

时间:2016-11-29 00:51:29

标签: hibernate

不用担心持久性,我设计了一个类来保存由(不同大小的)容器映射的不同产品的数量,产品可以保存在

df.astype({c: int for c in slc})

将Product和Container类作为

class Inventory {
  Long                             id;
  Map <Long, Map<Long,Integer>>    productQuantityByContainer; // ProductId->(ContainerId -> quantity)
}

后两者对其相应的数据库表具有直接的Hibernate映射。我需要使用Hibernate映射文件(hbm.xml),我的数据库有以下信息(不考虑Hibernate的约束):

class Product {
  Long  id;
  String name;
}

class Container {
  Long     id;
  Double   size;
}

我的问题是:我理解Hibernate不允许持久存储集合。因此,要使Hibernate持久保存来自Inventory类的信息,我的设计和映射是否足以满足以下要求? (我创建了两个类ContainerQuantity和Quantity,带有两个同名的映射表,如下所示)请批评/检查下面的hbm映射。

Product table
--------------
ID|Name
1  Milk
2  Orange Juice

Container table
---------------
ID |Size(oz)
10  32  
11  64

Inventory table (first 2 columns form the PK)
---------------
Product-ID(FK) | Container-ID(FK) | Quantity
  1              10                   25
  1              11                   15
  2              10                   33

1 个答案:

答案 0 :(得分:0)

经过多次苦难(并且没有答案即将发布),我找到了解决自己问题的方法。希望这将有助于其他人。我确实简化了我的设计以摆脱Quantity类,因为ContainerQuantity中的地图可以只是一个值集合。但是,值得注意的是,没有Quantity类并不能阻止我们在数据库中使用“数量”表。

// classes defined in package hibtest
public class Inventory {
  Long            id;
  String          name;
  Map <Product, ContainerQuantity>    cqsByProduct;

  public Inventory()
  //..getters and setters for each of above
}

public class ContainerQuantity {
   Long                  id;
   Inventory             inventory;
   Map<Container,Integer>     quantitiesByContainer;

   public ContainerQuantity()
  //..getters and setters for each of above
}

最困难的部分是让Hibernate映射正确,结果是:

<hibernate-mapping>
  <class name="hibtest.Inventory" table="INVENTORY">
     <id name="id" column="INVENTORY_ID">
        <generator class="sequence">
            <param name="sequence">DON.NEXT_INVENTORY_ID</param>
        </generator>
     </id>
     <property name="name" column="name" type="string"/>
     <map name="cqsByProduct" inverse="true" cascade="all"> <!-- inverse=true ensures INVENTORY_ID in CONTAINERQUANTITY table is set by hibtest.ContainerQuantity -->
        <key column="INVENTORY_ID" not-null="true"/>
        <map-key-many-to-many column="PRODUCT_ID" class="hibtest.Product"/>
        <one-to-many class="hibtest.ContainerQuantity"/>
     </map>
  </class>

  <class name="hibtest.ContainerQuantity" table="CONTAINERQUANTITY">
     <id name="id" column="CQ_ID">
        <generator class="sequence">
            <param name="sequence">DON.NEXT_CONTAINERQUANTITY_ID</param>
        </generator>
     </id>

     <many-to-one name="inventory" class="hibtest.Inventory" column="INVENTORY_ID" not-null="true" /> <!-- column will be set when row inserted into CONTAINERQUANTITY table -->

     <map name="quantitiesByContainer" table="QUANTITY" cascade="all" > <!--  inverse is false so CQ_ID in QUANTITY will be set by ContainerQuantity -->
       <key column="CQ_ID" not-null="true"/>
       <map-key-many-to-many column="CONTAINER_ID" class="hibtest.Container"/>       
       <element column="quantity" type="int"/>
     </map>
  </class>
 </hibernate-mapping>

我的表看起来如此(Oracle sql):

create table product
(
  id               NUMBER(22) not null,
  name             VARCHAR2(32) not null);

create table container
(
  id             NUMBER(22) not null,
  name           VARCHAR2(32) not null);

create table inventory
(
 INVENTORY_ID             NUMBER(22) not null,
 name                     VARCHAR2(32) not null);

create table containerquantity
(
 cq_id                    NUMBER(22) not null,
 product_id               NUMBER(22),
 inventory_id             NUMBER(22));

create table quantity
(
 quantity                 NUMBER(10) not null,
 container_id             NUMBER(22) not null,
 cq_id                    NUMBER(22) not null);

以下是驱动程序代码:

private static void persist(Session session){
    Product product1 = new Product();
    Product product2 = new Product();       
    product1.setName("Apple");
    product2.setName("Milk");

    Container c1 = new Container();
    Container c2 = new Container();
    c1.setName("32 oz");
    c2.setName("64 oz");

    //-- Make container-qty1 and add 2 quantity entries into it
    ContainerQuantity cq1 = new ContainerQuantity();

    Map<Container,Integer>     quantitiesByContainer1 = new HashMap<Container,Integer>();

    quantitiesByContainer1.put(c1, Integer.valueOf(25));
    quantitiesByContainer1.put(c2, Integer.valueOf(15));
    cq1.setQuantitiesByContainer(quantitiesByContainer1);

    //-- Make container-qty2 and add 1 quantity entry into it
    ContainerQuantity cq2 = new ContainerQuantity();

    Map<Container,Integer>     quantitiesByContainer2 = new HashMap<Container,Integer>();

    quantitiesByContainer2.put(c1, Integer.valueOf(33));
    cq2.setQuantitiesByContainer(quantitiesByContainer2);

    //-- Make Inventory object 
    Inventory inv = new Inventory(); inv.setName("foods");
    Map <Product, ContainerQuantity>    cqsByProduct = new HashMap<Product, ContainerQuantity>();
    cqsByProduct.put(product1, cq1);
    cqsByProduct.put(product2, cq2);

    //-- Set back-reference to inventory on ContainerQuantity objects 
    cq1.setInventory(inv);
    cq2.setInventory(inv);

    inv.setCqsByProduct(cqsByProduct);      

    session.save(product1);
    session.save(product2);
    session.save(c1);
    session.save(c2);

    session.save(inv);      
}