【问题标题】:JPA: Foreign key that is also a primary key mappingJPA:外键也是主键映射
【发布时间】:2015-02-03 00:52:33
【问题描述】:

我一整天都在尝试解决这个问题,但没有运气!我也尝试阅读网上的大部分教程,但你们都知道,它们都充满了无用的示例,无法反映您在现实世界中的需要。

这是我的情况:

数据库:

table: vehicles(vehicleId, brand, model, devYear, regNumber)

table: extras(vehicleId, allowSmoke, allowFood, allowDrinks, airConditioner)

关键是,如果我有一个类 Vehicle 和一个类 TravelExtras 映射到数据库,我希望 Vehicle 类有一个属性 TravelExtras travelExtras 和 get 和 set 方法。

不幸的是,当我尝试将对象持久保存在数据库中时,无论我尝试了什么,我都会遇到各种错误。

这是一个插图:

        EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "NaStopPU" );
        EntityManager entitymanager = emfactory.createEntityManager( );
        entitymanager.getTransaction( ).begin( );


        TravelExtra travelExtra = new TravelExtra();


        entitymanager.persist(travelExtra);


        Vehicle vehicle = new Vehicle(2L, "10152487958556242", "Mazda", "626", "334343", 2005, 4);  
        vehicle.setTravelExtra(travelExtra);

        entitymanager.persist(vehicle);



        entitymanager.getTransaction().commit();
        entitymanager.close( );

        emfactory.close( );

任何人都知道这种一对一的情况要使用什么样的注释吗?

【问题讨论】:

  • 您是否有充分的理由不允许 JPA 提供程序向 vehiclesextras 添加额外的 FK 列?
  • 您正在尝试使用相同的 PK 创建 OneToOne 映射?在这种情况下,您应该为每个表有单独的 PK,在这种情况下,主实体上的 CascadeType.ALL 是车辆。否则,如果您有“是”关系,则在 JPA 中对两个表使用相同的 PK 是有意义的
  • 你的例子没有意义。 Vehicle 是 TravelExtra PK 的一部分。但是,现在您首先插入 TravelExtra,而您没有指代任何车辆。插入时它根本不是有效的 PK。

标签: java database jpa orm


【解决方案1】:

Java Persistence wikibook 有一个名为 Primary Keys through OneToOne and ManyToOne Relationships 的部分,这似乎表明您想要的东西是可能的。

如果我没看错,对于你的情况,它看起来像:

class Vehicle {
    @Id
    @Column(name = "EXTRAS_ID")
    private long extrasId;

    @OneToOne(mappedBy="vehicle", cascade=CascadeType.ALL)
    private TravelExtra extras;
}

class TravelExtras {
    @Id
    @Column(name = "VEHICLE_ID")
    private long vehicleId;

    @OneToOne
    @PrimaryKeyJoinColumn(name="VEHICLE_ID", referencedColumnName="EXTRAS_ID")
    private Vehicle vehicle;

    public TravelExtras(Vehicle vehicle) {
        this.vehicleId = vehicle.getId();
        this.vehicle = vehicle;
    }
}

请注意,您的一个实体需要确保它与另一个实体具有相同的 id,这在示例中由 TravelExtras 构造函数完成,该构造函数需要绑定到的 Vehicle。

【讨论】:

  • 不应该只有一侧定义@PKJC而另一侧具有'mappedBy'属性吗?
  • 我不希望 TravelExtras 引用 Vehicle
  • 对象关系是双向的。你必须有双方的参考。我建议找一些关于 JPA 的文章或教程。它可以帮助您了解它的工作原理。
  • 为什么不简单地使用@Embedded解决所有问题?
  • @FelipeLeão -- 我也在寻找更多关于您正在使用的方法的讨论(@Embedded)您能推荐更多阅读材料吗?
【解决方案2】:

例如,您可以使用 Netbeans 映射您的类。它将生成注释。问题可能出在您的 dao 层。您必须以正确的方式持久化对象。例如,没有 Vehicle 就无法保存 travelExtra。还要注意拥有方。

【讨论】:

    【解决方案3】:

    为什么不使用@Embedded 对象?使用嵌入对象时,您会得到 您希望在代码中实现逻辑分离,并使您的数据库符合实体关系规范化规则。

    考虑一对一关系很奇怪,因为即使 JPA/Hibernate 允许它,所有数据都应该存储在同一个表中,使您的建模更简单,同时还通过删除简化查询和提高数据库性能需要加入操作。

    使用嵌入式对象时,您不必担心映射 ID 和奇怪的关系,因为您的 ORM 能够理解您只是进行代码分离,而不是要求表之间的实际关系是一对一.

    class Vehicle {
        @Id
        @Column(name = "ID")
        private long vehicleId; 
        @Column(name = "BRAND")
        private String brand; 
        @Column(name = "MODEL")
        private String model;
        @Column(name = "DEV_YEAR")
        private int devYear;
        @Column(name = "REG_NUMBER")
        private int regNumber;
    
        @Embedded
        private TravelExtra extras;
    
        // Constructor, getters and setters...
    
    }
    

    .

    @Embeddable
    class TravelExtras {
    
        @Column(name = "ALLOW_SMOKE")
        private boolean allowSmoke; 
        @Column(name = "ALLOW_FOOD")
        private boolean allowFood;
        @Column(name = "ALLOW_DRINKS")
        private boolean allowDrinks;
        @Column(name = "AIR_CONDITIONER")
        private boolean airConditioner;
    
        // Default Constructor, getters and setters...
    }
    

    【讨论】:

      【解决方案4】:

      我知道这是非常古老的 qs,但为了您的案例的完整性 你可以只拥有(jpa 2.0)

      @Entity
      @Data
      public class Vehicle implements Serializable{
         @Id
         @GeneratedValue
         private long vehicleId;
         .. //other props
      }
      
      @Entity
      @Data
      public class VehicleExtras implements Serializable{
               @Id
               @OneToOne (cascade = CASCADE.ALL)
               @MapsId
               @JoinColumn(name ="vehicleId")
               private Vehicle vehicle;
      
               @Column  
               private boolean allowSmoke; 
               ..// other props.
      }
      

      应该为 VehicleExtra 表共享相同的 pk/fk

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-18
        • 2019-04-22
        • 1970-01-01
        • 2017-08-06
        • 2017-01-03
        • 1970-01-01
        • 2021-07-01
        • 1970-01-01
        相关资源
        最近更新 更多