4

I'm working on architecting a somewhat enterprise-level solution and have a question about how to best handle the persistence details.

My overall setup is that there's a core set of business logic/objects, as well as a number of isolated components that rely on the core logic, but never on other components. Sitting on top of this component/core business logic layer is application logic and presentation stuff. Underneath these two layers is infrastructure and persistence.

general layout

note: currently I'm working on the Core specifically, haven't gotten into Components yet

My Current Persistence Implementation:

Currently (and incorrectly, I suspect), my Core project has a reference to the Persistence project, and a Core model (Orders, let's say) has an IOrderRepository field. When the Order is instantiated, I can pull up the info, I can save it, etc.

My Current Concern:

1) My core domain objects are not following SRP because they essentially have persistence details attached to them (despite those details being interface details rather than implementation details, it's still there).

2) Upon reading a good article on managing EF's DbContext (which can be considered in a more generic context form than EF specifically) (ref: http://mehdi.me/ambient-dbcontext-in-ef6/) - I've realized that it makes little sense to loading a persistence context when a domain object is loaded, because it's not at all representative to the context in which the objects are used (e.g., the objects could be loaded under any number of contexts) (note also that I haven't forgotten about Aggregates, but not included here for simplicity because the end result is the same, I think).

What Seems Better:

It "feels" better to me that the persistence context (and thus the DbContext and thus the repositories) should be handled under the general context of any specific business task rather than simply on a business object, which, in itself, has no true context despite the fact they do encapsulate various behaviors (is this statement correct??).

Considering that a persistence context/dbContext is can essentially be considered a transaction, it thus seems more correct in an architecture sense that such persistence context should in fact be included where these driving actions begin, as this is the context in which they essentially operate.

What I Can't Seem to Grasp:

How do I set this up so the persistence context is closer to the context in which it's used (which feels right, but correct me if I'm wrong), while at the same time fully separating it from the domain objects so those latter maintain their required SRP (e.g., so I don't have Save() and Load() methods on the domain objects, no matter how well abstracted away they are)?

I appreciate any input on how to best keep this from turning into a tangled-up mess. Thanks

jleach
  • 2,632
  • 9
  • 27
  • Upon reading some "related questions", I think I may have found a suitable answer (looks like I might want each app project managing interaction with the repositories on their own (as per my suspicion), so perhaps a mini-layer in there for that). I have to run for a bit but will enter a new answer w/ the references after I get back and have time to work it out. – jleach Nov 24 '15 at 12:06
  • why the downvote? how can I be more clear? – jleach Nov 24 '15 at 13:06
  • Any time we venture into "enterprise" decisions, things get too complicated very quickly. I voted to close as "too broad". There are a million reason why any single answer would be incorrect for another project. Even if it feels correct to you, it's not correct in a general sense. Anytime there's no clear-cut correct answer, the question is not a good fit for Programmers. – Scant Roger Nov 24 '15 at 13:23
  • 1
    Thanks for the explanation. I've posted a question to meta asking where these are better accepted (if anywhere): http://meta.programmers.stackexchange.com/questions/7754/where-to-as-too-broad-questions – jleach Nov 24 '15 at 13:30
  • It baffles me that "Core logic" is depending on anything. Especially persistence, which too complicated for being "core anything". – Euphoric Nov 24 '15 at 13:36

1 Answers1

2

Taking a few hints from the following two posts (apparently SE's search abilities are better than mine...), I've come up with something that seems to fit well.

Are Persistence-Ignorant objects able to implement lazy loading?

Where to validate domain model rules that depend on database content?

It appears what I'm looking for are ObjectProviders. Essentially, these live outside the scope of the domain objects themselves and are tied to a particular application layer piece. Their role is to instantiate the domain objects as required and manage the persistence of them (though, the persistence implementation itself still lives in the bottom persistence layer).

So, the application layers will not interact directly with the domain object POCOs themselves, but will instead generate them through these providers.

Having the providers be per-application section allows me to implement the details as required per context (e.g., application A might only need to load X part of the object graph, where application B might need X and Y, etc.)

The diagram below isn't the prettiest but describes the layout well enough:

Architecture revised with providers

Now the domain objects themselves are completely freed of the persistence layer and the persistence management itself is closer to the context in which it's used (while the persistence implementation remains isolated in it's own layer).

This likely isn't 100% perfect: I'm sure there's further details I'll have to smooth out, but from a 30kft view, it does seem much better.

With that said, I'm still open to exploring other ideas, so if you have one feel free to spit it out. Thanks

jleach
  • 2,632
  • 9
  • 27
  • So everything needs Database? What if different db's are needed? What about storing big blobs? I've seen these kind of diagrams before. They end up in a managers presentation and a developers trash bin. Enterprise-architecture often misses one point, and that is 'it should work'. – Pinoniq Nov 25 '15 at 12:22
  • I also don't get why a Managed domain object needs Core Logic. A domain object is just stom data-representation, struct, array, or getter/Setter class. If it is more it is bad design. I also dont get what the arrows mean. Depend on? require? control-flow? If you want your work to be actually used in a working project, try to keep it simple. Not every developer is one the same level. – Pinoniq Nov 25 '15 at 12:24
  • Sorry, but you're quite wrong (on a number of levels, but specifically on your understanding of a domain model: what you describe is an anemic domain model, which is typically an anti-pattern, depending on the overall approach). Unfortunately I can't explain it all here in comment(s) - perhaps with some more enterprise experience you'll recognize what's what. A good start can be found at ISBN 978-0-7356-8535-2. – jleach Nov 25 '15 at 12:37