【问题标题】:How to model packages, versions and licenses?如何对包、版本和许可证进行建模?
【发布时间】:2021-06-20 00:47:17
【问题描述】:

我目前有点卡住了。问题在于 npm 包、它们的版本/发行版和它们的许可证。

这是一个简单的许可证

CREATE TABLE IF NOT EXISTS license (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    reference TEXT NOT NULL,
    is_deprecated_license_id BOOLEAN NOT NULL,
    reference_number INTEGER NOT NULL,
    license_id TEXT NOT NULL,
    is_osi_approved BOOLEAN NOT NULL
);

INSERT INTO license
     ("name",reference,is_deprecated_license_id,reference_number,license_id,is_osi_approved)
VALUES
     ('Academic Free License v2.0','./AFL-2.0.json',false,0,'AFL-2.0',true);

这是我的包裹

CREATE TABLE IF NOT EXISTS npm_package (
    id BIGSERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    description TEXT NOT NULL
);

INSERT INTO npm_package 
    (name, description)
VALUES
    ('react', 'React is a JavaScript library for building user interfaces.'),
    ('react-router-dom', 'DOM bindings for React Router'),
    ('typescript', 'TypeScript is a language for application scale JavaScript development'),
    ('react-dom', 'React package for working with the DOM.');

一个包有多个版本,每个版本都有许可证,例如

  • 反应 - 1.0.0 - 麻省理工学院
  • 反应 - 2.0.0 - BSD
  • 反应 - 3.0.0 - 麻省理工学院
  • ...

版本只是一个 semver 字符串。

CREATE TABLE IF NOT EXISTS npm_version (
    npm_package_id BIGINT NOT NULL REFERENCES npm_package,
    version TEXT NOT NULL,
    license_id INTEGER NOT NULL REFERENCES license
)

现在我正在尝试使用 Spring Boot 和 Hibernate 对此进行建模。这是我到目前为止所得到的。

@Entity
public class License {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  private String reference;

  private Boolean isDeprecatedLicenseId;

  private Integer referenceNumber;

  private String name;

  private String licenseId;

  private Boolean isOsiApproved;
}

这是我的 npm 包。

@Entity
public class NpmPackage {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  private String description;
}

现在我想组合包、它们的版本和它们的许可证。我将如何继续使用 Hibernate?我正在寻找的查询类似于“给我所有带有相应许可证的 'react' 版本”

非常感谢!


编辑 24/03/2021

我做了一些更多的研究并走得更远。让我们暂时移除许可,关注软件包和版本。

这是我创建包的方法。

CREATE TABLE IF NOT EXISTS npm_package (
    id BIGSERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    description TEXT NOT NULL
);

INSERT INTO npm_package 
    (name, description)
VALUES
    ('react', 'React is a JavaScript library for building user interfaces.'),
    ('react-router-dom', 'DOM bindings for React Router'),
    ('typescript', 'TypeScript is a language for application scale JavaScript development'),
    ('react-dom', 'React package for working with the DOM.');

这是我创建版本的方法。版本不需要额外的标识符。包和版本的组合是独一无二的。

CREATE TABLE IF NOT EXISTS npm_package_version (
    npm_package_id BIGINT NOT NULL REFERENCES npm_package,
    version TEXT NOT NULL,

    UNIQUE(npm_package_id, version)
)

这里是NpmPackage.java

@Entity
public class NpmPackage {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany
  private List<NpmPackageVersion> versions;

  private String name;

  private String description;
}

这里是NpmPackageVersion.java

@Entity
public class NpmPackageVersion {

    @EmbeddedId
    private NpmPackageIdVersion npmPackageIdVersion;

    @MapsId("npmPackageId")
    @ManyToOne
    private NpmPackage npmPackage;

    @Embeddable
    public class NpmPackageIdVersion implements Serializable {
        private static final long serialVersionUID = 3357194191099820556L;

        private Long npmPackageId;

        private String version;
    }
}

没有@MapsId 我得到了

表 [npm_package_version] 包含由多个逻辑列名引用的物理列名 [npm_package_id]:[npm_package_id]、[npmPackageId]

@MapsId 我明白了

架构验证:表 [npm_package_versions] 中缺少列 [versions_npm_package_id]

当我将列重命名为 versions_npm_package_id 我得到

架构验证:表 [npm_package_versions] 中缺少列 [npm_package_id]

我绕着圈子跑,却什么也没有。很久没有觉得自己这么傻了。每当我开始使用新技术时,我仍在等待“点击”事件。不幸的是,这还没有发生:)

有什么想法吗?

【问题讨论】:

  • 任务的哪一部分有问题?你应该在NpmPackage 中有一个@OneToMany @JoinColumn private List&lt;Version&gt; versions,在Version 中有一个@ManyToOne private License license。示例见herehere
  • 我是 Hibernate 的新手,也许我的心智模型目前太复杂了。我也有 Hibernate 抱怨缺少 Id 的问题:没有为实体 NpmVersion 指定标识符。
  • 每个实体都需要有一个 id。对于NpmVersion,您需要一个id,类似于NpmPackage 中的那个。或者,您可以创建和映射由包 ID 和版本字符串组成的 composite primary key
  • 我不想为npm_version 创建额外的标识列。它更像是一个连接表。这意味着我必须使用@EmbeddedId,对吧?
  • 您可以使用@EmbeddedId@IdClass,无论哪个对您有吸引力

标签: java postgresql spring-boot hibernate


【解决方案1】:

您已经非常接近找到解决方案了。

以下设置有效:

NpmPackage

@Entity
@Table(name = "npm_package")
public class NpmPackage {

  public NpmPackage(String name, String description) {
    this.name = name;
    this.description = description;
  }

  public NpmPackage() {
  }

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  private String description;

  @OneToMany(mappedBy = "npmPackage", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
  private List<NpmPackageVersion> versions = new ArrayList<>();

  ...//getters and setters

  public void addVersion(NpmPackageVersion version) {
    this.versions.add(version);
    version.setNpmPackage(this);
  }

  public void removeVersion(NpmPackageVersion version) {
    this.versions.remove(version);
  }
}

NpmPackageVersion

@Entity
@Table(name = "npm_package_version")
public class NpmPackageVersion {

    public NpmPackageVersion(String version, License license) {
        setVersion(version);
        this.license = license;
    }

    public NpmPackageVersion() {
    }

    @EmbeddedId
    private NpmPackageIdVersion npmPackageIdVersion = new NpmPackageIdVersion();

    @MapsId("npmPackageId")
    @ManyToOne
    private NpmPackage npmPackage;

    @ManyToOne
    private License license;

    public String getVersion() {
        return npmPackageIdVersion.version;
    }

    public void setVersion(String version) {
        npmPackageIdVersion.version = version;
    }

    ...//getters and setters

    @Embeddable
    public static class NpmPackageIdVersion implements Serializable {
        private static final long serialVersionUID = 3357194191099820556L;

        private Long npmPackageId;

        private String version;

        ... //getters and setters etc.
    }
}

许可证

@Entity
@Table(name = "license")
public class License {

    public License() {}

    public License(String name, String licenseId) {
        this.name = name;
        this.licenseId = licenseId;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String reference;

    @Column(name = "is_deprecated_license_id")
    private boolean deprecatedLicenseId;

    private Integer referenceNumber;

    private String name;

    private String licenseId;

    @Column(name = "is_osi_approved")
    private boolean osiApproved;

    ... //getters and setters
}

我用下面的代码测试了一下:

@Transactional
public NpmPackage createPackage() {
        License license = new License("General Public License", "GPL 2.0");
        em.persist(license);
        NpmPackage npmPackage = new NpmPackage("react", "React Framework");
        npmPackage.addVersion(new NpmPackageVersion("8.11.0", license));
        em.persist(npmPackage);
}

【讨论】:

  • 谢谢?你?
  • 最后一个问题:如果我不喜欢使用FetchType.EAGER,那将如何工作?目前我遇到了一个错误。 > 原因:org.hibernate.LazyInitializationException:未能延迟初始化角色集合:com.example.bom.NpmPackage.NpmPackage.versions,无法初始化代理 - 没有会话
  • 如果您切换到LAZY,则在访问NpmPackage.versions 时,您仍需要处于事务的上下文中(同时会话仍处于打开状态)。另一种选择是,如果您看到针对每个包发出两个查询并且担心性能,则将@Fetch(JOIN) 放在versions 之上。您还可以在需要时使用连接提取:SELECT p FROM NpmPackage p JOIN FETCH p.versions。最后,使用嵌入的 id,您可以简单地查询所有版本:SELECT v FROM NpmPackage Version v WHERE v.npmPackageIdVersion.npmPackageId = :id
  • 不确定这是否能回答您的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
  • 1970-01-01
  • 2012-09-03
  • 2011-02-07
  • 2014-06-14
  • 2017-06-28
相关资源
最近更新 更多