【问题标题】:How to create relationships in entities correctly如何正确地在实体中创建关系
【发布时间】:2022-01-08 00:50:27
【问题描述】:

描述机器的实体

@Entity
@Table(name = "machine")
public class Machine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;      
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "machine_node", joinColumns = @JoinColumn(name = "machine_id"), inverseJoinColumns = @JoinColumn(name = "node_id"))
    private List<NodeMachine> nodeMachines = new ArrayList<>();
}

描述部分/节点的实体

@Entity
@Table(name = "node_machine")
public class NodeMachine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

在每台机器上安装了几个部件(nodeMachines列表),每个部件可以安装在不同的机器上,所以添加了ManyToMany。

例如,轮子可以安装在摩托车或汽车上。摩托车可以有两个轮子,汽车可以有四个。

我将更详细地描述表格中的内容。我必须马上说这个例子不是很成功,只是为了理解。在机器表中,我们有 100 M 摩托车 (1-100) 和 100 C 汽车 (1-100)。并且 NodeMachine 表中只有一个条目——K1 车轮,它适用于所有一百辆摩托车和所有一百辆汽车。由此无法确定每辆摩托车和每辆汽车应该有多少个轮子。因此,我认为应该有第三张表,其中标明了每辆汽车和摩托车的轮数。而且我认为在表中保留 200 条摩托车车轮记录和 400 条汽车记录太多余了。

每个部件都以特定数量安装在特定机器上。 我想通过知道节点和机器名称来获取安装在特定机器上的节点数。 为此,您必须使用字段创建另一个 count_machine_node 表

- machine_id
- node_id
- count

我知道您必须创建一个新实体。

@Entity
@Table(name = "node_machine")
public class CountNodeMachine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long machine_id;
    private Long node_id;
    private Integer count;
}

但是您需要在这些实体中注册哪些连接?

如何正确链接这三个表?

我需要创建一个 CountNodeMachine 实体吗?

【问题讨论】:

    标签: java spring-data-jpa


    【解决方案1】:

    您不需要第三个实体,因为您可以进行 sql 查询,或者按名称选择机器,过滤它的 nodeMachines 列表并计算结果。

    例如,使用存储库,如here,您可以按 id 选择机器,或按名称选择机器列表,然后只需按名称和计数过滤它(他们的)节点列表。

    import java.util.List;
    
    import org.springframework.data.repository.CrudRepository;
    
    public interface MachineRepository extends CrudRepository<Machine, Long> {   
      List<Machine> findByName(String lastName);
    }
    

    在您的代码中的某处:

    @Autowired
    private MachineRepository machineRepository;
    
    public int countNodesInMachine(String machineName, String nodeName) {
        return machineRepository.findByName(machineName).stream()
            .flatMap(machine -> machine.getNodeMachines().stream())
            .filter(node -> node.getName().equals(nodeName))
            .count();
    }
    

    【讨论】:

    • 我不明白为什么这让你感到困惑。我没有说一个节点只能安装在一台机器上。为了清楚起见,我举了一个例子。
    • 谢谢,这是有道理的。无论如何,您可能不需要第三个实体。您可以使用简单的查询或存储库来选择您需要的内容。
    • 我不明白该怎么做。应该指定哪些连接。
    • 这个选项也不适合,还有记录条数的统计。我在底部的答案中详细描述了这种情况。
    【解决方案2】:

    我总是建议从 Java 端开始开发。所以,可能是这样的

    @Entity
    @Table(name = "machine")
    public class Machine {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        // Список узлов машины
        @ElementCollection
        private Map<NodeMachine, Integer> nodeMachines = new HashMap<>();
    }
    

    另外,请查看我的Hibernate articles(俄语和英语版本)

    【讨论】:

    • 在我看来这种方法不是很合适。我们有一辆可以有两个 K 轮的 M1 摩托车和一辆可以有四个 K 轮的 C1 汽车。根据这种方法,我将在 NodeMachine 表中为 M1 提供两个条目 K(1-2),为 C1 提供四个条目 K(3-6)。
    • 但这是多余的信息。并且当表中有 100 辆摩托车时,需要为它们存储 200 条车轮记录吗?在 NodeMachine 中只有一个条目 K1,它适用于 M1 和 C1,并且可能适用于其他 100 辆摩托车。但是在这种情况下,您的方法将不起作用。这个例子是有条件的,只是为了演示。
    • 您的 cmets 似乎与以下解决方案有关!我的建议是有 3 个表:第一个用于机器,第二个用于 nodeMachine,第三个用于每台机器的节点数。但我建议不要创建第三个实体或创建冗余存储库方法,而是将其隐藏在 Map 下。换句话说,我的意思是事先创建方便的Java域模型,然后才将其存储到数据库中(实际上,Hibernate会为您完成,只需添加一些注释即可)
    • 毕竟会创建第三张表。好的,我会检查你的选择。如果它有效,那么这就是我需要的!
    • 您的代码正在运行。那只是我无法从 NodeMachine 表中获取机器列表。事实证明,应将 ManyToMany 注释添加到 NodeMachine 实体中。但是现在,在 Machine 实体中,使用了 ElementCollection 而不是 ManyToMany。我不知道如何将 NodeMachine 中的 ManyToMany 映射到 Machine 中的 ElementCollection?
    【解决方案3】:

    为此,您可以在 NodeMachine 实体中创建一个计数器。这在数据库中占用的空间方面是经济的,但在面向对象方面却不是这样。使用 CountNodeMachine 实体根本不经济,因为一个表被浪费了来保存一个数字。我认为您需要一个具有 NodeMachine 及其计数的包装类。并将此列表用于机器实体。

    【讨论】:

    • 这样不行。我详细描述了一切。您了解将有一个 NodeMachine 条目,并且它可以具有任意数量的计数字段(5 或 10 或 100)。从理论上讲,每台机器可能会有所不同。以及如何在这里为每个 NodeMachine 记录获取任意数量的计数器?
    【解决方案4】:

    如果这符合目的,请发表评论。

    机器实体:

    @Entity
    @Table(name = "machine")
    public class Machine {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @OneToMany(mappedBy="machineId")
        List<MachinePartCount> count;
    

    零件实体

    @Entity
    @Table(name = "part")
    public class Part {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @OneToMany(mappedBy="partId")
        List<MachinePartCount> count;
    

    关系实体

    @Entity
    @Table(name="machine_part")
    @IdClass(MachinePartCountPK.class)
    public class MachinePartCount {
        
        
        @Id
        private Integer machineId;
        
        @Id
        private Integer partId;
            
        private Integer count;
        
    

    复合键

    @Embeddable
    public class MachinePartCountPK implements Serializable{
    
        private static final long serialVersionUID = 1L;
    
        private Integer machineId;
        
        private Integer partId;
    

    输出:

        **machineService.findAll()**
        getAllMachines: [Machine [id=1, name=m1, count=[MachinePartCount [machineId=1, partId=1, count=2]]], Machine [id=2, name=m2, count=[MachinePartCount [machineId=2, partId=102, count=4]]]]
        
        **partService.findAll()**
        getAllParts: [Part [id=1, name=p100, count=[MachinePartCount [machineId=1, partId=1, count=2]]], Part [id=102, name=p10, count=[MachinePartCount [machineId=2, partId=102, count=4]]]]
    
        **machinePartCountService.findAll()**
        getmachinePartEntries: [MachinePartCount [machineId=1, partId=1, count=2], MachinePartCount [machineId=2, partId=102, count=4]]
    

    表格中的数据: 机台: machine 零件表: part machine_part 表: machine_part

    【讨论】:

    • 你能edit你的答案更好地解释你改变了什么,为什么这会解决问题以及如何解决?
    • 机器和零件之间的联系在哪里?
    【解决方案5】:

    如果我从上面的例子中得到, 您可以做的是创建第三个实体,即Categories

    因为您拥有特定于机器的类别,例如摩托车或汽车。 他们有一套特定的轮子。

    您可以在第三个表中映射它并与机器创建关系。

    `类别

    身份证|类别|轮子|其他节点

    1 |汽车 | 4 | 1

    2 |自行车 | 2 | 3`

    等等,你只需要从机器表中找到类别和节点并轻松获得计数,你也可以添加新的节点。

    唯一的缺点是您的机器将特定于类别

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多