简体   繁体   English

JPA 具有相同数据库和额外属性的多对多关系

[英]JPA Many-To-Many Relationship with same DB and extra Attribute

I need a Many-To-Many Relationship within the same Database.我需要同一个数据库中的多对多关系。 I don't mind creating mapping databases, but I want to have only one Entity in the end.我不介意创建映射数据库,但我希望最终只有一个实体。

Let's say I've got a resource which can have many resources (Sub-Resources).假设我有一个可以有很多资源(子资源)的资源。 What I need is an Resource with the Sub-Resources and also the count of them because one Resource can have x resources.我需要的是一个带有子资源的资源以及它们的数量,因为一个资源可以有 x 个资源。

Essentially, I need this with the extra Attribute of the count of Sub resources needed for the Resource.本质上,我需要此资源所需的子资源计数的额外属性。

@Table(name = "resources")
public class Resources {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column
    private String name;

    @ManyToMany
    private Collection<Resources> subResources;
    
} 

To clarify that a bit, at best I would have something like that:为了澄清一点,充其量我会有类似的东西:

@Table(name = "resources")
public class Resources {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column
    private String name;

    @ManyToMany
    private HashMap<Resources, Integer /* count */> subResources;
    
} 

I know how it works with two tables (Resources & Sub Resources) and a mapping type, but I couldn't figure out how to do it as described above, since Resources can be Sub-Resources at the same time.我知道它是如何与两个表(资源和子资源)和一个映射类型一起工作的,但我不知道如何按照上述方式进行操作,因为资源可以同时是子资源。

Thanks in advance提前致谢

EDIT: I need an extra Attribute in the mapping table where I can set the amount of sub resources as an Integer编辑:我需要映射表中的一个额外属性,我可以在其中将子资源的数量设置为 Integer

The configuration yo have will work for a unidirectional relationship.您拥有的配置将适用于单向关系。 There is no technical problem, only you will not be able to specify the multiple parents of a subresource, so in the end it is not many to many.没有技术问题,只是你不能指定一个子资源的多个父母,所以最终不是多对多。

To make it trully many to many you need another field on the Resources class to define the inverse side of the relationship;为了使其真正成为多对多,您需要Resources class上的另一个字段来定义关系的反面; I have added the @JoinTable annotation to make the names in the join table explicit, but it is optional if the defaults are good enough for you;我添加了@JoinTable注释以明确连接表中的名称,但如果默认值对您来说足够好,则它是可选的; I also switched from the vary basic Collection to List ;我也从不同的基本Collection切换到List I would prefer Set and you would have to provide equals and hashCode on the entity.我更喜欢Set并且您必须在实体上提供equalshashCode Finally I am always initializing the collection-valued fields ( ArrayList here; HashSet if you go for Set ), so as to avoid silly NullPointerException s or complex initialization code:最后,我总是初始化集合值字段(此处为ArrayList ;如果您使用 go 为Set ,则为HashSet ),以避免愚蠢的NullPointerException或复杂的初始化代码:

    @ManyToMany
    @JoinTable(
            name = "RESOURCE_SUBRESOURCE",
            joinColumns = @JoinColumn(name = "resource_id"),
            inverseJoinColumns = @JoinColumn(name = "subresource_id")
    )
    private List<Resource> subResources = new ArrayList<>();

    // the mappedBy signals that this is the inverse side of the relation, not a new relation altogether
    @ManyToMany(mappedBy = "subResources")
    private List<Resource> parentResources = new ArrayList<>();

Use as:用于:

    Resources r1 = new Resources();
    r1.setName("alpha");
    em.persist(r1);

    Resources r2 = new Resources();
    r2.setName("beta");
    r2.getSubResources().add(r1);
    em.persist(r2);

    Resources r3 = new Resources();
    r3.setName("gama");
    em.persist(r3);

    Resources r4 = new Resources();
    r4.setName("delta");
    // won't work, you need to set the owning side of the relationship, not the inverse:
    r4.setParentResources(Arrays.asList(r2, r3));
    // will work like this:
    r2.getSubResources().add(r4);
    r3.getSubResources().add(r4);
    // I believe that the order of the following operations is important, unless you set cascade on the relationship
    em.persist(r4);
    r2 = em.merge(r2);
    r3 = em.merge(r3);

As for the count: In the question you mention that you want a count of related objects.至于计数:在您提到您想要相关对象的计数的问题中。 While specific JPA providers (Hibernate, EclipseLink) may allow you to accomplish this (using a read-only field that is populated by an aggragate query - COUNT(*) FROM JoinTable WHERE resource_id=? ), it is not standard.虽然特定的 JPA 提供程序(Hibernate、EclipseLink)可能允许您完成此操作(使用由聚合查询填充的只读字段 - COUNT(*) FROM JoinTable WHERE resource_id=? ),但它不是标准的。 You can always do resource.getSubResources().size() , but that would fetch all the subresources into memory, which is not a good thing and might in fact be a really bad thing if you call in frequently or there are many sub/parent resources.您总是可以执行resource.getSubResources().size() ,但这会将所有子资源提取到 memory 中,这不是一件好事,如果您经常调用或有很多子/父资源。

I would prefer to run a separate count query, perhaps even for a set of resource ids, whenever I really need this.每当我真正需要它时,我宁愿运行一个单独的计数查询,甚至可能是一组资源 ID。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM