Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA-实体设计问题_Java_Jpa_Entity_Entity Relationship_Object Relationships - Fatal编程技术网

Java JPA-实体设计问题

Java JPA-实体设计问题,java,jpa,entity,entity-relationship,object-relationships,Java,Jpa,Entity,Entity Relationship,Object Relationships,我正在开发一个Java桌面应用程序,并使用JPA进行持久化。我有一个问题提到如下: 我有两个实体: 国家 城市 国家/地区具有以下属性: 国家名称(PK) 城市具有以下属性: 城市名称 现在,由于在两个不同的国家/地区可以有两个同名城市,因此数据库中City表的primaryKey是由CityName和CountryName组成的复合主键 现在我的问题是如何在Java中将城市的主键实现为实体 现在我们知道从Country到City的关系是OneToMany,为了在上面的代码中显示这种

我正在开发一个Java桌面应用程序,并使用JPA进行持久化。我有一个问题提到如下:

我有两个实体:

  • 国家
  • 城市
国家/地区具有以下属性:

  • 国家名称(PK)
城市具有以下属性:

  • 城市名称
现在,由于在两个不同的国家/地区可以有两个同名城市,因此数据库中City表的primaryKey是由
CityName
CountryName
组成的复合主键

现在我的问题是如何在Java中将
城市
的主键实现为
实体

现在我们知道从
Country
City
的关系是
OneToMany
,为了在上面的代码中显示这种关系,我在
City
类中添加了
Country
变量

但是,我们在
城市
类”对象中的两个地方存储了重复数据(
countryName
),一个在
国家
对象中,另一个在
城市pk
对象中

但另一方面,两者都是必要的:


  • cityPK
    对象中的
    countryName
    是必需的,因为我们以这种方式实现复合主键


  • country
    对象中的
    countryName
    是必需的,因为它是显示对象之间关系的标准方式


如何解决此问题?

CityPK
中的
countryName
应使用
@列(insertable=false,updateable=false)
标记为只读,并且两个
countryName
应映射到同一列(使用
name
属性):


IMO处理此类问题的正确方法是使用生成的内部(通常为
Long
)ID,而不是自然主键-这消除了整个问题。当然,这需要修改您的DB模式,但是从您的帖子中我假设这是可能的

@Entity
public class City implements Serializable {
    private Long id;

    private String name;
    private Country country;

    @Id
    @GeneratedValue
    @Column(name = "CITY_ID")
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }

    // more getters, setters and annotations
}

这是处理这类问题的标准方法吗?这个问题在JPA中常见吗?@Yatendra:是的,这是一种标准的方法(如果你不使用代理键,就像Peter建议的那样)。然后我认为我不能在equals方法中使用
id
,来实现相等。对吗?@Yatendra为什么不?两个名称相同但国家不同的城市必须有不同的ID。您只需确保不会在表中两次插入同一国家的同一城市。这可以由DB触发器或Hibernate拦截器强制执行。您不能在
equals()
中使用
id
,因为
id
是由数据库生成的。并且在对象持久化之前不可用。请参阅Gavin King的“使用Hibernate的Java持久化”,请参阅关于业务密钥和代理密钥的讨论。@Ram,只有当您需要在两个尚未持久化的实体之间进行比较时,这才是一个问题(这不是很常见,但我可能错了)。在这种情况下,如果
id
null
,则可以扩展
equals
以比较其他重要属性。或者,如果我们执行
new City()
并将其添加到
集合中,则会出现问题。因为ID可以更改。我也不确定,但那是书上说的。
  @Entity
  public class City implements Serializable {
           @EmbeddedId
           private CityPK cityPK;

           @ManyToOne
           @JoinColumn(name = "countryName")
           private Country country;
  }


   @Embeddable
   public class CityPK implements Serializable {
       public String cityName;

       @Column(name = "countryName", insertable = false, updatable = false)
       public String countryName;
   }
@Entity
public class City implements Serializable {
    private Long id;

    private String name;
    private Country country;

    @Id
    @GeneratedValue
    @Column(name = "CITY_ID")
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }

    // more getters, setters and annotations
}