2017-10-11 126 views
1

我知道这是一个常见问题,但我还没有找到另一个解决我的疑惑。永久模型到域模型映射而不暴露域对象属性

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

@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 */ 
    } 
} 

我的问题出现,如果我想hava不同的持久性模型。然后我会碰到这样的:

/* 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 */ 
} 

我的问题是,我怎么能映射到SomeEntityDAO不SomeEntity暴露SomeEntity的属性?

如果我创建了一个构造函数,例如:public SomeEntity(String attribute1, String attribute2, ...) {},那么任何人都可以创建SomeEntity的无效实例。如果我在SomeEntity中公开所有setter,则会发生同样的情况。

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

我在考虑让所有的setter受到保护,所以DAO可以扩展实体并有权访问setters ......但我不确定这是否是一个好选择。

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

+0

你想要一个ORM,它允许没有setter或有私人setter的实体类? –

+0

我指的是域模型类而不暴露公共设置者。只公开行为方法。吸气者很好。 ORM类可以有getter和getters。 –

回答

0

域实体应该是自我验证的,这意味着它应该只根据其内部值进行验证。如果更新需要依赖于外部依赖的验证,那么我会创建一个负责更新的更新类。从updater类中,可以使用规范模式(作为可注入的依赖项)来实现验证。

修改时使用域实体,而只读投影使用DTO。当您以只读方式使用直线DTO时,会有性能和简化收益。这用于CQRS模式。

class SomeEntity { 
    private Long id; 
    private String attribute1; 
    private String attribute2; 
    private String attribute3; 
    // ... other attributes 

    public SomeEntity() {} 

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

    public String getAttribute1() { ... } 

    public String getAttribute2() { ... } 

    public Long setId() { ... } 

    public String setAttribute1() { ... } 

    public String setAttribute2() { ... } 
} 

//classes/interfaces named for clarity 
class EntityUpdater implements IEntityUpdater { 
    public EntityUpdater (ISpecification spec){ 
    } 

    public updateEntity(SomeEntity entity){ 
    //assert/execute validation 
    } 
} 
1

我有同样的问题。而环顾四周,我找不到解决方案。相信我,如果它存在的话隐藏在某个地方。没有任何建议表明当你需要处理一个旧的项目时,ORM实体无处不在,而且Domain和ORM模型之间有一大步。

鉴于此,我已经推断如果你真的想让你的域实体保持纯粹(所以没有得到和设置 - 后者我永远不会接受!)你必须做一些交易。因为没有给实体一些额外的知识,没有办法共享内部。请注意,这并不意味着您必须让域实体知道ORM层,也不需要使用getter。只是,我已经得出结论,域实体应该有办法将它们暴露为不同的模型。

所以,总而言之,我会在你的情况下做的是建立一个访客模式。域实体实体A将实现接口EntityAVisitor或类似的东西。

interface EntityAVisitable { 
    accepts(EntityAVisitor visitor); 
} 

构建器实现由访客所需要的接口,EntityAVisitor

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

版本()接口EntityAVisitor使用通用型T.这样域实体是不可知的关于具体执行EntityAVisitor的返回类型的功能。

完美吗?没有什么好的解决办法,就是摆脱ORM(实际上我会说我讨厌他们,因为这种方式大多数时候都是错误的 - 但这是我个人的想法)。

这很好吗?

由于语言限制(我想你使用Java),不允许有一个很好的解决方案。

它是封装您的域实体的真实内容的好工作吗?是。

不仅如此,您可以通过这种方式准确地确定可能暴露的内容和方式。所以,在我看来,保持实体纯粹和必须与座位上的ORM合作是很好的。