我知道这是一个常见的问题,但是我还没有找到解决我的疑问的另一个问题。

通常,如果项目很小,我会在表示域对象的同一对象中添加持久性注释。这允许从数据库加载实体并保持所有设置者为私有,从而确保任何实例始终处于有效状态。就像是:

@Entity
class SomeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    // ... other attributes

    protected SomeEntity() {}

    /* Public getters */
    public Long getId() { ... }

    public String getAttribute1() { ... }

    public String getAttribute2() {  ... }

    /* Expose some behaviour */
    public void updateAttributes(String attribute1, String attribute2) {
       /* do some validations before updating */
    }
}


如果我要使用其他持久模型,则会出现我的问题。然后我会有类似的东西:

/* SomeEntity without persistent info */
class SomeEntity {
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    // ... other attributes

    protected SomeEntity() {}

    /* Public getters */
    public Long getId() { ... }

    public String getAttribute1() { ... }

    public String getAttribute2() {  ... }

    /* Expose some behaviour */
    public void updateAttributes(String attribute1, String attribute2) {
       /* do some validations before updating */
    }
}


和DAO:

@Entity
class SomeEntityDAO {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;

    public SomeEntityDAO() {}

    /* All getters and setters */
}


我的问题是,如何在不暴露SomeEntity属性的情况下将SomeEntityDAO映射到SomeEntity?

如果创建类似public SomeEntity(String attribute1, String attribute2, ...) {}的构造函数,则任何人都可以创建SomeEntity的无效实例。如果我在SomeEntity中公开所有二传手,也会发生同样的情况。

我也不认为使用updateAttributes()构建对象是一个有效的解决方案,因为这将执行一些我现在不想执行的验证(我们相信数据库中持久化的数据)。

我正在考虑保护所有的设置者,以便DAO可以扩展Entity并可以访问设置者...但是我不确定这是否是一个好选择。

解决此问题的最佳或通用方法是哪种?

最佳答案

我遇到过同样的问题。环顾四周,我找不到解决方案。相信我,如果存在的话很好地藏在某个地方。没有一个建议可以解决当您必须处理一个老项目时该怎么做的问题,ORM实体无处不在,并且在Domain和ORM模型之间迈出了一大步。

鉴于此,我推断出,如果您真的想保持Domain实体纯净(因此无法获取和设置-我永远也不会接受!),您必须进行一些交易。因为如果不给实体提供一些额外的知识,就无法共享内部信息。当心,这并不意味着您必须使Domain实体知道ORM层,也不意味着您必须使用getter。就像我得出的结论一样,域实体应该具有将它们公开为不同模型的方法。

因此,总而言之,在您遇到的情况下,我要做的是建立访客模式。域实体EntityA将实现EntityAVisitable接口以接受EntityAVisitor或类似的东西。

interface EntityAVisitable {
   accepts(EntityAVisitor visitor);
}


构建器实现来访者EntityAVisitor所需的接口。

interface EntityAVisitor<T>{
    setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
    <T> build();
}


接口EntityAVisitor的build()函数使用通用类型T。通过这种方式,域实体与EntityAVisitor的具体实现的返回类型无关。

完美吗?没有。

完美的解决方案是摆脱ORM(实际上我会说我讨厌它们,因为在大多数情况下使用的方式是错误的-但这是我个人的想法)。

是不是不错?没有。

由于语言限制,不允许使用任何好的解决方案(我想您使用Java)。

封装域实体的真实内容是否很好?是。

不仅如此,您还可以准确地决定可能公开的内容以及如何公开。因此,我认为,在保持实体纯净与必须与位于座位下的ORM一起工作之间是一个很好的选择。

10-06 09:04