【问题标题】:Both key column and map-key are PKkey column 和 map-key 都是 PK
【发布时间】:2014-07-24 04:03:18
【问题描述】:

如何创建一个同时具有键列和映射键作为详细信息类 PK 的一部分的映射属性?

像这样:

<class entity-name="Person"  >
    <id name="id"/>
    <property name="birthDate" type="date"/>
    <map name="names">
        <key column="personId"/>
        <map-key type="string" column="code"/>
        <one-to-many class="PersonName" />
    </map>
</class>


<class entity-name="PersonName">
    <composite-id>
        <key-many-to-one name="personId" class="Person"/>
        <key-property name="code" type="string" length="32"/>
    </composite-id>
    <property name="lastName" type="string" length="64" index="nameSearch"/>
    <property name="firstName" type="string" length="64" index="nameSearch"/>
    <property name="middleName" type="string" length="64" index="nameSearch"/>
    <property name="isActual" type="boolean"/>
</class>

我需要避免在 PersonName 类中创建需要特殊处理的代理键。下面显示的 Json 应该会自动持久化到数据库中,在必要时根据 PersonId-code 键插入和更新详细记录。

“代码”属性很自然地与人员 ID 一起标识行。

我尝试了“inverse”、“not-null”等的不同组合。我承认我没有完全理解它是如何工作的。我收到不同的错误消息,例如:

错误:“person”列中的空值违反了 NOT NULL 约束
详细信息:错误行包含(null、null、lastname、ffffirst、null、null)。

或:

org.hibernate.MappingException:实体映射中的重复列: PersonName 列:人(应使用 insert="false" update="false" 映射)

如果表示为 json,应该是这样的:

{
    "birthDate": "33-44-55",
    "names": {
        "mainName": {
            "lastName": "lastname",
            "firstName": "ffffirst"
        },
        "maidenName": {
            "lastName": "lastname1",
            "firstName": "ffffirst2"
        },
        "old": {
            "lastName": "lastname3",
            "firstName": "ffffirst4"
        }

    }
}

UPD(澄清问题) 实际上这是一个主要目标 - 使用此 json 发布时,系统应该创建主文件和所有详细信息。这个 json 被转换成映射的类。如果 master 填充了“id”,系统应该更新 master 和 details,并在需要时添加新条目。详细信息(“名称”映射条目)不应指定任何代理“id”。它们由master的“personId”字段和“code”字段标识。

** 说明 2 ** 如示例 json 所示,映射键是字符串,而不是复合键。从映射 xml 中可以看出,这都是动态映射。不应编写无法从 json 自动实例化的其他类。

希望有可能!

获取全图,表格生成OK,我喜欢:

CREATE TABLE personname
(
  personid character varying(32) NOT NULL,
  code character varying(32) NOT NULL,
  lastname character varying(64),
  firstname character varying(64),
  middlename character varying(64),
  isactual boolean,
  CONSTRAINT personname_pkey PRIMARY KEY (personid, code),
  CONSTRAINT fk_1skg5frawyftx8co9uawhc3r8 FOREIGN KEY (personid)
      REFERENCES person (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

【问题讨论】:

  • 亲爱的,我会接受hibernate无法帮助我实现我想要的答案。它有很多特性,包括指定映射键的能力,但是这个特性并不意味着在细节表中它会被限制为一个映射键有多个条目。地图键只是装饰意义

标签: java hibernate jpa orm hibernate-mapping


【解决方案1】:

这是不可能的。使用 mongodb 或编写自己的 ORM。

【讨论】:

  • 这是可能的,但不适用于您当前的域模型。对于每个 Json 映射,您都需要一个关联表。问题是:值得吗?也许你需要一个 json 存储。
  • 这意味着其他事情是可能的,但不是我要问的。在“名称”映射定义中,键列和映射键应指向其他表的 PK。不是一个映射键应该由两个字段组成,抱歉。是的,它是人们能想到的细节地图的最佳模型。如果 map key 不是 PK 的一部分,两个值可以映射到一个 map key,这是错误的。当 hibernate 作者介绍了一个很好的映射键概念但存在缺陷时,他们在想什么?
  • 是的,ORM 很棘手,并且不严格支持 JSON。我希望你能通过 Hibernate 找到答案,但如果你愿意做一些更具体的事情,我建议你使用 Postgres Hstore 或 MongoDb。
【解决方案2】:

我认为您的映射应该如下所示:

对于嵌入的复合 id,您需要一个嵌套的 Key 类(例如 Person$Key,尽管它也可以是一个外部类):

public static class Key {
    private Long personId;
    private String code;

    public Key(Long personId, String code) {
        this.personId = personId;
        this.code = code;
    }

    public Long getPersonId() {
        return personId;
    }

    public String getCode() {
        return code;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Key)) {
            return false;
        }
        Key k = (Key)obj;
        return personId.equals(k.personId) && code.equals(k.code);
    }

    @Override
    public int hashCode() {
        return 37*personId.hashCode() + code.hashCode();
    }
}

那么你的地图会是这样的:

private Map<Key,PersonName> names = new HashMap<Key,PersonName>();

Hibernate 映射:

<class entity-name="Person"  >
     <id name="id" column="id">
        <generator class="native"/>
    </id>
    <property name="birthDate" type="date"/>
    <map name="names" inverse="true">
        <composite-map-key class="Person$Key">
            <key-property name="personId"/>
            <key-property name="code"/>
        </composite-map-key>
        <one-to-many class="PersonName" />
    </map>
</class>

<class entity-name="PersonName">
    <composite-id name="id" class="Person">
        <key-property name="personId"/>
        <key-property name="code"/>
    </composite-id>
    <many-to-one name="person" class="Person"
        insert="false" update="false">
        <column name="personId"/>
        <column name="code"/>
    </many-to-one>
    <property name="lastName" type="string" length="64" index="nameSearch"/>
    <property name="firstName" type="string" length="64" index="nameSearch"/>
    <property name="middleName" type="string" length="64" index="nameSearch"/>
    <property name="isActual" type="boolean"/>
</class>

【讨论】:

  • 似乎我将失去为一个人拥有多个人名的能力。尝试使用复合键来更新您的建议或修改解决方案...
  • 一个人可以有多个人名,这是一对多的映射。
  • 一个 Person 的 PersonNames 在 personId 字段中是否具有相同的值?
  • 我更新了我的示例,使 Person 和 PersonName 都具有合成 id,因此您可以为同一个 Person 拥有更多 PersonName。
  • 谢谢,虽然这不是我想要的。我想避免在 PersonName 中使用代理 id。人名应由人名和“代码”唯一标识。我不反对在 PersonName 中有一个特殊的 id,但我不希望它出现在任何 json 中并让客户端存储和跟踪这个 id 及其与人和代码的对应关系。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 2020-01-16
相关资源
最近更新 更多