2017-10-11 103 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合作是很好的。