3

I know this is a common question, but I haven't found another that solves my doubts.

Usually, if the project is small, I've persistence annotations in the same object that represents the domain object. This allows to load the entity from database and keep all the setters private, ensuring any instance is always in a valid state. Something like:

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

My problem appears if I want to have a different persistent model. Then I would have something like:

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

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

My question is, how can I map SomeEntityDAO to SomeEntity without exposing SomeEntity's attributes?

If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity. The same occurs if I make all setters public in SomeEntity.

I also don't think is a valid solution build the object using updateAttributes() since this will execute some validations I don't whant to execute at this point (we trust the data that's persistet in database).

I'm thinking in having all the setters protected, so the DAO can extend the Entity and have access to setters... but I'm not sure if this is a good option.

Which is the best or common approach to solve this problem?

  • 1
    I never tried this by myself, so only a comment here, but I guess what you are after is some kind of automapper like Dozer. That should allow easily to map SomeEntity to SomeEntityDAO. – Doc Brown Oct 11 '17 at 10:58
  • Mapping objects with some tool that uses reflection to access private fields could be a solution (assuming some performance cost). I would like to know how people is solving this issue so it could be an answer. Thanks for your comment. – Tobías Oct 11 '17 at 11:22
-2

If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity.

Models shouldn't be responsible for their own validation because validation is business logic, and business logic should be defined outside of the model. So I would recommend removing updateAttributes from SomeEntity, putting the logic elsewhere, and giving SomeEntity a public constructor.

Typically models are created from some kind of input (user request, file input, std input), your business logic should validate this input before constructing your model.

You probably don't have to validate the models being loaded from the database because you would assume they are already valid, but you could using the same validation logic before converting SomeEntityDAO into SomeEntity. Whether you use a reflection based mapping tool at that point doesn't really matter.

  • Any comments for the downvotes? – Samuel Oct 11 '17 at 22:07
  • I think it’s your use of the word “model”, you seem to be treating it as synonymous with “Entity” as defined by something like EntityFramework. But I don’t think that’s the right use of the term “model”. And as a result your answer is confusing relative to a lot of other uses of the term. – RibaldEddie Oct 12 '17 at 5:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.