【问题标题】:What is the appropriate way persist extended classes?持久化扩展类的适当方法是什么?
【发布时间】:2014-11-07 12:55:40
【问题描述】:

考虑图表:

我与 JPA 合作了很短的时间,到目前为止,我从来没有需要持久化扩展类...正如您在示例中看到的那样,SNMPNodeIPNode 等是所有来自Node 的扩展类也从GeoLocation 扩展。

我知道我可以用@MappedSuperclassIPNode 注释主类,SNMPNode 将继承它们的属性以进行持久化...但是在这种情况下,我最终会得到几乎相同的表,并且据我了解,而不是这样做,我可以将 Node 中的所有信息分组并使用单个表。

这是JPA工作中扩展类的持久化方式还是我的概念有误?

与恢复的代码相同:

public class Node extends GeoLocation {
    private String name;
    private Group group;
    private Location location;
    private Type type;
    private Company company;
}

public class IPNode extends Node {
    private Long id;
    private String ipAddress;
}

public class SNMPNode extends Node {
    private Long id;
    private SNMPServer server;
}

[[在此点回答后编辑]]

为了做出贡献,以下是我最终所做的示例:

INode:

public interface INode {
    public Long getId();
    public void setId(Long id);

    public String getName();
    public void setName(String name);

    public String getIpAddress();
    public void setIpAddress(String ipAddress);

    public String getCommunity();
    public void setCommunity(String community);
}

节点:

@Entity
@DiscriminatorValue("N")
@DiscriminatorColumn(name="NODE_TYPE",discriminatorType=DiscriminatorType.STRING, length=20)
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Node extends GeoLocation implements INode {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}

    (... Overrides from INode ...)
}

IP节点:

@Entity
@DiscriminatorValue("I")
public class IPNode extends Node {
    private String ipAddress;

    public String getIpAddress() { return this.ipAddress;}
    public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }

    (... Overrides from INode ...)
}

SNMP节点:

@Entity
@DiscriminatorValue("S")
public class SNMPNode extends Node {
    private String community;

    public String getCommunity() { return community;}
    public void setCommunity(String community) { this.community = community; }

    (... Overrides from INode ...)
}

节点存储库:

@Repository
public interface NodeRepository extends JpaRepository<Node, Long> { }

所以现在我可以做这样的事情了:

@ContextConfiguration("classpath:/spring/application-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class NodeRepositoryTest {

    @Autowired
    NodeRepository repo;

    private INode node;

    @Before
    @Transactional
    @Rollback(false)
    public void setup() {
        node = new IPNode();
        node.setName("ipNode");
        node.setIpAddress("1.1.1.1");
        repo.save((IPNode)node);

        node = new SNMPNode();
        node.setName("snmpNode");
        node.setIpAddress("2.2.2.2");
        node.setCommunity("some text");
        repo.save((SNMPNode)node);
    }

    @Test
    @Transactional
    public void Test() throws Exception {
        INode testNode = repo.findOne(1L);
        assertNotNull(testNode);
    }
}

两种节点类型都保存在同一张表上,因此它们的键不能重复...我的 REST URL 可以通过 /nodes/1 或 /nodes/2 获取它们,这毕竟是我的主要目标...

谢谢:)

【问题讨论】:

标签: java spring hibernate jpa spring-data-jpa


【解决方案1】:

如果您的基类使用@MappedSuperclass 进行注释,则继承仅在 OOP 上下文中相关。 @MappedSuperclass 属性被简单地复制到每个子类关联的数据库表中,您只能查询子类实体。

Single table inheritance 以无法声明所有特定子类属性不可为空为代价产生最佳性能(不涉及连接或联合)(因为所有基类和所有子类特定属性都属于单个数据库表)。

使用joined inheritance tables,您可以在基本数据库表中拥有基类属性,并且每个特定的子类都有自己的关联表。子类表通过 FK 与基础数据库表链接,因此您需要连接这些表以获取子类实体。相对于@MappedSuperclass,基类是可查询的,因为 OOP 上下文和数据库都反映了继承模型。

【讨论】:

  • 您的回答以及这些文档en.wikibooks.org/wiki/Java_Persistence/Inheritance 让我很容易理解。谢谢。我主要担心的是,这将是一个 REST 应用程序,并且将使用 /nodes/ 之类的 URL 检索节点。但是我想要 IPNode 或 SNMPNode 的相同 URL,并且这些类上的 ID 不起作用,因为它们可以重复......我想我需要一个带有 ID 字段的抽象 Node 类,然后在任何表继承之间做出决定.
  • @MarcelusTrojahn,我正在尝试遵循这些示例,但不幸的是,您提供的链接与 Vlad 回复中的链接之间存在不一致之处。查看连接的继承示例;注释不同。
猜你喜欢
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 2010-09-28
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
相关资源
最近更新 更多