I'd go with Option 3, with the following notes:
- Try and reduce the amount of domain logic that your clients need to know to get the job done. Create services that expose that data in meaningful (to your clients) ways, so that you can request collections of domain objects which fulfil certain criteria, rather than doing that crunching on your client.
- Validation should be considered optional on the client-side as, you can never guarantee that future client implementations are going to be done properly. Therefore, always validate on the server side as if it hadn't been done elsewhere. Of course, clients should be validating on the client-side too.
- Rather than mapping the WCF data back to full domain objects on the client side, consider mapping them to simpler ViewModel-type objects - a slimmed down version of your full domain objects only containing properties appropriate to the client - makes client programming simpler.
The problem you're still faced with is lots of mapping. I guess this price is worth paying (and made easier with a tool such as AutoMapper) because removing the client dependency on your domain model gives you breathing room to change your domain, tweak the mapping, without breaking any client code.
You can take either approach and have it work well - there are, of course, pros and cons.
Entity Framework is definitely intended to suffuse your domain entities. It does work well when your domain entities and data entities are the same classes. It's much nicer if you can rely on EF to keep track of the changes for you, and just call context.SaveChanges()
when you're finished with your transactional work. It also means that your validation attributes don't have to be set twice, once on your domain models and once on your persisted entities - things like [Required]
or [StringLength(x)]
can be checked in your business logic, allowing you to catch invalid data states before you try to do a DB transaction and get an EntityValidationException
. Finally, it's quick to code - you don't need to write a mapping layer or repository, but can instead work directly with the EF context. It's already a repository and a unit of work, so extra layers of abstraction don't accomplish anything.
A downside to combining your domain and persisted entities is that you end up with a bunch of [NotMapped]
attributes scattered throughout your properties. Often, you will want domain-specific properties which are either get-only filters on persisted data, or are set later in your business logic and not persisted back into your database. Some times, you'll want to express your data in your domain models in a way that doesn't work very well with a database - for example, when using enums, Entity will map these to an int
column - but perhaps you want to map them to a human-readable string
, so you don't need to consult a lookup when examining the database. Then you end up with a string
property which is mapped, an enum
property which isn't (but gets the string and maps to the enum), and an API which exposes both! Similarly, if you want to combine complex types (tables) across contexts, you may wind up with a mapped
OtherTableId and an unmapped ComplexType
property, both of which are exposed as public on your class. This can be confusing for someone who isn't familiar with the project, and unnecessarily bloats your domain models.
The more complex my business logic/domain, the more restrictive or cumbersome I find combining my domain and persisted entities to be. For projects with short deadlines, or that don't express a complex business layer, I feel that using EF entities for both purposes is appropriate, and there's no need to abstract your domain away from your persistence. For projects which need maximum ease-of-extension, or that need to express very complicated logic, I think you're better off separating the two and dealing with the extra persistence complexity.
One trick to avoiding the trouble of manually tracking your entity changes is to store the corresponding persisted entity ID in your domain model. This can be filled automatically by your mapping layer. Then, when you need to persist a change back to EF, retrieve the relevant persistent entity before doing any mapping. Then when you map the changes, EF will detect them automatically, and you can call context.SaveChanges()
without having to track them by hand.
public class OrganisationService
{
public void PersistLicenses(IList<DomainLicenses> licenses)
{
using (var context = new EFContext())
{
foreach (DomainLicense license in licenses)
{
var persistedLicense = context.Licenses.Find(pl => pl.Id == license.PersistedId);
MappingService.Map(persistedLicense, license); //Right-left mapping
context.Update(persistedLicense);
}
context.SaveChanges();
}
}
}
Best Answer
Repository is a service of domain model, that has responsibility of serving as layer between your domain and data store. It should have method to query entities and methods to save and update them.
To answer your question:
Also, if you are using an ORM framework, then this framework is already form of repository. Make full use of it and don't reinvent the wheel or add unnecessary layer of complexity over it.