3

My question is very simple: How do get my class's private data to the Repository to save?

Regardless of the architectural style we adopt, everyone agrees that business objects shouldn't know "how" to save themselves - that is they shouldn't implement database or other persistence details. However, it seems to me that business objects are the only ones who know "what" they need to save. The Repository knows how to fetch from the database, but if it is to know how to translate a business object into database terms, then it must know what to translate.

Consider that I may use a database, but I'm not marking my classes up with hibernate annotations because I might just as often save to a flat text file.

Assuming my classes here are actually named after specific business entities, What would be wrong with doing something like

interface Exporter
{
    public void Export(String id, String value1, String value2);
}

interface Repository
{
    public Entity FindById(String id);
}

class Entity
{
    private String id;
    private String value1;
    private String value2;
    private String derivedvalue;

    public Entity() {}

    public Entity(String id, String value1, String value2)
    {
        this.id = id;
        this.value1 = value1;
        this.value2 = value2;
        this.derivedvalue = /* derived from id, value1, and value2 */;
    }

    public void DoBusiness()
    {
        // ...
    }

    public void Export(Exporter exporter)
    {
        Exporter.Export(this.id, this.value1, this.value2);
    }
}

and using it like

FlatFileRepositoryAndExporter flatfile = new FlatFileRepositoryAndExporter(...);
Entity entity = flatfile.FindById(...);

// Do business logic
entity.DoBusiness();

entity.Export(flatfile);

I understand there are frameworks that can assist me, but at the end of the day, they all rely on reflection of some sort. I want to know, without reflection, how can I statically compose my objects to expose their data while maintaining encapsulation. The only answer I can come up with is this visitor pattern.

Mark Murfin
  • 684
  • 6
  • 19
  • This is fine. I've done something similar where I inject dependencies into entities to do various things (such as persistence) and it's worked very well for me. – Matt Crouch Jun 19 '15 at 18:56
  • Visitor patterns is ok but it adds some noise to the domain entity. You're right saying that all frameworks and persistence clients are using reflections save and retrieve objects. The simplest would be an xml or json serializer that would work without any mapping. The same is generally valid for NoSQL databases. Adding persistence logic to your domain would force you to start testing it, which is not really part of the domain test. If you want to serialize to some file, you can always implement your repository as a generic list and use some serialization to persist it to the file system. – Alexey Zimarev Jun 20 '15 at 19:33

2 Answers2

1

Don't complicate your life too much. What you're trying to do is basically a memento, which works but it has high (as in very boring) maintenance cost. I usually json serialize things regardless where I actually store them and I've configured json.net to serialize protected properties. So basically, I have protected properties or just protected setters and it works quite well.

While not a purist solution, the compromise is very low, the object's internals are not exposed to its user. And you can have stuff like

 private List<string>_data=new List<string>();
public IEnumerable<string> Data 
{
   get { return _data;}
   protected set {  _data=value.ToList(); }

}

This approach is simple enough, very maintainable and persistence tool agnostic.

Btw, an exporter, considering its purpose, should deal only with public members and the object shouldn't know about it.

MikeSW
  • 15,292
  • 3
  • 33
  • 50
1

I tend to agree with @MikeSW that making external persistence tools able to collect domain object state, with the help of minor scope adjustments (or reflection as ORMs do), is often simpler than letting the domain object itself control entirely what is persisted.

There's a third way which consists in making the entity emit events describing what happened instead of exposing its state -- that's Event Sourcing. Then whoever wants can listen to those and persist changes in whatever form they want to derive.

guillaume31
  • 12,725
  • 28
  • 43