2

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 hava 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?

Tobías
  • 6,142
  • 4
  • 36
  • 62
  • You would like an ORM that allows entity classes that have no setters or have private setters? – Jeff Miller Oct 13 '17 at 13:28
  • I mean domain model classes without exposing public setters. Exposing only behaviour methods . Getters are fine. And the ORM classes can have getters and getters. – Tobías Oct 14 '17 at 15:34

3 Answers3

1

Domain entity should be self-validating meaning it should only validate itself based on it's internal values. If update requires validation that depends on external dependencies, then I would create an updater class that is responsible for the update. From the updater class, you can use specification pattern (as an injectable dependency) to implement the validation.

Use domain entities when modifying, and DTOs for read-only projections. There are performance and simplification gains when you use straight DTOs in read-only. This is used in CQRS patterns.

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
  }
}
alltej
  • 6,787
  • 10
  • 46
  • 87
1

I've had the same kind of problem. And looking around I've found no solution. Believe me, if it exists is well hidden somewhere. None that suggests what to do when you have to deal with an old project where ORM entities are everywhere and there's a big step between Domain and ORM model.

Given this, I've deducted that if you really want to keep your Domain entities pure (so non get and set - the latter I would NEVER accept!) you have to do some deals. Because there's no way to share the internals without giving the entities some extra knowledge. Beware, this doesn't mean that you have to make the Domain entities aware of the ORM layer, nor that you have to use getters. Just, what I've concluded, the Domain entities should have ways to expose them as a different model.

So, in conclusion, what I would do in your situation is to build up a Visitor pattern. The Domain entity EntityA would implement the EntityAVisitable interface to accept a EntityAVisitor or something like this.

interface EntityAVisitable {
   accepts(EntityAVisitor visitor);
}

The builder implements the interface required by the Visitor, EntityAVisitor.

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

The build() function of the interface EntityAVisitor uses a generic type T. In this way the Domain entity is agnostic about the return type of the concrete implementation of the EntityAVisitor.

Is it perfect? No.

Perfect solution would be to get rid of the ORM (actually I would say that I hate them, because the way are used is most of the times wrong - but this is my personal thought).

Is it nice? No.

A nice solution is not allowed due to language restrictions (I suppose you use Java).

Does it a good work in encapsulating the real content of your Domain entity? Yes.

Not only, in this way you can decide exactly what could be exposed and how. So, in my opinion, is a good deal between keeping the entity pure and having to work with an ORM under the seat.

Luca Masera
  • 672
  • 7
  • 18
0

Some ORMs allow setting entity values through field access (as opposed to setter methods).

JPA uses the @Access annotation. See What is the purpose of AccessType.FIELD, AccessType.PROPERTY and @Access

I created an ORM, sormula, that can use field access. See @Row fieldAccess and test case org.sormula.tests.fieldaccess.

Jeff Miller
  • 1,424
  • 1
  • 10
  • 19