JPA - 使用弹簧数据

时间:2016-04-21 14:36:17

标签: hibernate jpa database-design spring-data

我很难尝试将最佳数据库设计(使用BCNF)映射到JPA实体。

我有3个实体:地点,人物和行动 在给定的地方,您有人在执行操作,我们也有他们在那里执行操作的次数。

请注意,每个实体都可以独立存在:您可以拥有一个没有执行任何操作的地方,一个没有执行任何操作的人和没有被任何人执行的操作。

为了存储该信息,我将数据库模式建模为:

DB design

现在我正在尝试创建JPA实体来映射它,这就是我遇到问题的地方。
我想遍历从这个地方开始的对象,从提取的地方遍历,以便遍历执行其中所有操作的所有人,最后让每个人能够看到他们在那个地方执行了哪些操作 他们做了多少次。

从纯SQL的角度来看,这很容易:

获取该地点的人员列表:

  • 从Place pl,Person pe,ActionPerformed ap中选择distinct(pe.name),其中ap.place_id = pl.id和ap.person_id = pe.id和pl.id =< place id >

然后,对于每个回来的人:

  • 从Place pl,Person pe,Action a,ActionPerformed ap中选择a.name,ap.count,其中ap.place_id = pl.id和ap.person_id = pe.id和ap.action_id = a.id和pl。 id =< place id >和pe.id =< person id >

我想使用那种向下钻取行为在JPA实体中映射它:

  • 有一个Place实体,其中包含一个在其中执行操作的人员列表
  • 在Person实体中,有一个Actions列表及其各自的计数

这可能与JPA有关吗?或者我的想法是错误的?

这是我对实体的尝试:

从地点开始,引用人物:

public class Place implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    private String name;

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(
        name="ActionPerformed"
        , joinColumns={
            @JoinColumn(name="place_id", nullable=false)
            }
        , inverseJoinColumns={
            @JoinColumn(name="person_id", nullable=false)
            }
        )
    private List<Person> people;

    <getters, setters, etc...>
}

然后是人们,引用已执行的操作(带计数):

public class Person implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    private String name;

    @OneToMany(mappedBy="person", fetch=FetchType.EAGER)
    private List<ActionPerformed> actionsPerformed;

    <getters, setters, etc...>
}

这些行动主要是为了他们的名字:

public class Action implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    private String name;

    <getters, setters, etc...>
}

连接表和PK对象关联所有这些:

@Entity
public class ActionPerformed implements Serializable {
    @EmbeddedId
    private ActionPerformedPK pk;

    @Column(nullable=false)
    private Integer count;

    @ManyToOne
    @JoinColumn(name="place_id")
    private Place place;

    @ManyToOne
    @JoinColumn(name="person_id")
    private Person person;

    @ManyToOne
    @JoinColumn(name="action_id")
    private Action action;

    <getters, setters, etc...>
}

@Embeddable
public class ActionPerformedPK implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(name="place_id")
    private Integer placeId;

    @Column(name="person_id")
    private Integer personId;

    @Column(name="action_id")
    private Integer actionId;

    <getters, setters, etc...>
}

我看到的一个问题是,当我查询某个地点时,我为每个执行操作的人获取了多个条目 - 在连接表中每个条目一个。 此外,在检查每个人中列出的操作时,我会获得该人在每个地方执行的所有操作(无视发起查询的地点)。

有没有办法在JPA映射或实体设计中解决这个问题?或者我是否必须更改数据库设计?

P.S。:我已经检查了至少十几个与此类似的问题的帖子,但没有一个完全符合我正在尝试的设计,所以在那里提出的解决方案在我的案例中是行不通的。

P.S.2:我正在使用Spring Data和CrudRepositories从实体创建存储库。

P.S.3:请原谅我的语法不好或“奇怪”的句子,英语不是我的母语。

提前致谢!

1 个答案:

答案 0 :(得分:0)

我没有逐行检查您的代码,因为我认为您的问题并未通过数据库设计和类注释来回答,而是通过查询来解答。

如果你想在比尔在伦敦完成所有的动作表演,那就写下像

这样的东西
select ap from ActionPerformance ap where ap.person.name = "Bill" and ap.place.name = "London"

和JPQL将生成一些类似于你所描述的SQL。