n-tier architecture: best place to store business objects? - c#

Say I have a 3-tier architecture (UI, Business, and Data). Usually, I create a 4th project called "Model" or "Common" to keep my data access objects and each of the other projects would then use this project.
Now I'm working on a project where some of my data access objects have methods like Save() etc that need access to the Data project. So, I would have a circular reference if I attempted to use the Model/Common project in the Data project.
In this scenario, where is the best place to keep the data access objects? I could keep it within the Data project itself, but then my UI project which needs to know about the data access objects, would need to access the Data layer, which is not good.

I don't think you have your n-tier quite right. It sounds like you're building more 2-tier systems.
In a real 3-tier project, only your data tier is allowed to talk to the database. You have that with your "Model" or "Common" projects. Those projects are your data tier. But where you veer off is that only the business tier should be allowed to talk to them. Your presentation code should not be allowed to talk to the data tier projects at all.
n-Tier comes in when you have more than 3 "tiers", but the same principle appliers: each tier only knows how to use (and only needs a reference to) the one below it, and then provides an api for the tier above it. In my own projects, I take your typical presentation, business, and data tiers and provide a 4th "translation" tier between business and data. This way the data tier can return generic types like dataset, datatable, and datarow, and the business tier only has to work in terms of strongly-typed business objects. The translation tier only converts between the generic data objects and strongly-typed objects. This way a change to one of the traditional tiers is less likely to require a change in another.

This is what I have in my project.
1.) Application.Infrastructure
Base classes for all businessobjects, busines object collection, data-access classes and my custom attributes and utilities as extension methods, Generic validation framework. This determines overall behavior organization of my final .net application.
2.) Application.DataModel
Typed Dataset for the Database.
TableAdapters extended to incorporate Transactions and other features I may need.
3.) Application.DataAccess
Data access classes.
Actual place where Database actions are queried using underlying Typed Dataset.
4.) Application.DomainObjects
Business objects and Business object collections.
Enums.
5.) Application.BusinessLayer
Provides manager classes accessible from Presentation layer.
HttpHandlers.
My own Page base class.
More things go here..
6.) Application.WebClient or Application.WindowsClient
My presentation layer
Takes references from Application.BusinessLayer and Application.BusinessObjects.
Application.BusinessObjects are used across the application and they travel across all layers whenever neeeded [except Application.DataModel and Application.Infrastructure]
All my queries are defined only Application.DataModel.
Application.DataAccess returns or takes Business objects as part of any data-access operation. Business objects are created with the help of reflection attributes. Each business object is marked with an attribute mapping to target table in database and properties within the business object are marked with attributes mapping to target coloumn in respective data-base table.
My validation framework lets me validate each field with the help of designated ValidationAttribute.
My framrwork heavily uses Attributes to automate most of the tedious tasks like mapping and validation. I can also new feature as new aspect in the framework.
A sample business object would look like this in my application.
User.cs
[TableMapping("Users")]
public class User : EntityBase
{
#region Constructor(s)
public AppUser()
{
BookCollection = new BookCollection();
}
#endregion
#region Properties
#region Default Properties - Direct Field Mapping using DataFieldMappingAttribute
private System.Int32 _UserId;
private System.String _FirstName;
private System.String _LastName;
private System.String _UserName;
private System.Boolean _IsActive;
[DataFieldMapping("UserID")]
[DataObjectFieldAttribute(true, true, false)]
[NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
public override int Id
{
get
{
return _UserId;
}
set
{
_UserId = value;
}
}
[DataFieldMapping("UserName")]
[Searchable]
[NotNullOrEmpty(Message = "Username Is Required.")]
public string UserName
{
get
{
return _UserName;
}
set
{
_UserName = value;
}
}
[DataFieldMapping("FirstName")]
[Searchable]
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
[DataFieldMapping("LastName")]
[Searchable]
public string LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
[DataFieldMapping("IsActive")]
public bool IsActive
{
get
{
return _IsActive;
}
set
{
_IsActive = value;
}
}
#region One-To-Many Mappings
public BookCollection Books { get; set; }
#endregion
#region Derived Properties
public string FullName { get { return this.FirstName + " " + this.LastName; } }
#endregion
#endregion
public override bool Validate()
{
bool baseValid = base.Validate();
bool localValid = Books.Validate();
return baseValid && localValid;
}
}
BookCollection.cs
/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection()
{
}
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection (IList<Book> initialList)
: base(initialList)
{
}
}

The Data layer should store information in terms of rows and columns (maybe using typed DataSets, if you like), if you are using a relational backend. No "business objects".
The Business layer should use your "business objects". It can have a reference to the BusinessObjects project.
In summary:
UI has references to Business and BusinessObjects
Business has references to BusinessObjects and Data
Hope this helps.

I have a BusinessObjects project, server side storing the mappings (ORM) and a corresponding DataAccess service exposing CRUD operations on them (and others also like GetAll) etc.

I would suggest creating and interface of what you want in the model project, and implementing that definition in the data layer. That way all three (four?) projects can use that definition, without knowing how it's implemented.

In my opinion, only the business layer should have knowledge of the data access objects. It should use them for data operations while applying its own business rules and logic, then return dumb objects (e.g. data transfer objects) to the UI layer above.
You could use some thing like AutoMapper to automatically map between you data and business objects.

It really depend on the pattern, if you are using MVC (Front Controller Pattern), the model Is the domain-specific representation of the data upon which the application operates (generally an ORM help with this) we use a DATA project for this classes.
Models are not data access objects, so the data access becomes in form of repositories in a Different project. Services for Business Rules and finally the Web project. In this approach the Data.dll is referenced in all projects.
The Model is like omnipresent.
DATA(Domain Model) -> REPOSITORY(Data Access) -> SERVICE(Business Rules) -> WEB

Related

DDD (Domain Driven Design) Application Layer

I have been trying to build an application based on DDD but I have some questions.
Some layers that I have:
- Presentation Layer - MVC
- Application Layer
- Domain Layer
...
First of all, I would like to know if I can do this in the ApplicationLayer (get family info > get default message info > send an email > updated the database):
public ApproveFamilyOutput ApproveFamily(ApproveFamilyInput input)
{
Family family = _familyRepository.GetFamily(input.Username);
family.Approve();
DefaultMessage defaultMessage = _defaultMessageRepository.GetDefaultMessage(MessageTypes.FamilyApproved);
_email.Send(family.GetEmail(), defaultMessage.Subject, defaultMessage.Message);
_familyRepository.Update(family);
bool isSaved = _familyRepository.Save();
return new ApproveFamilyOutput()
{
Errors = Helper.GetErrorIfNotSaved(isSaved)
};
}
Am I thinking well? Is the Application layer responsible to do that job?
The second question is: I need to send some data to the presentation layer according to the privileges that the user has. These privileges are defined in the database. Example:
- The object Family have the Name, LastName, PhoneNumber, Email properties and the user can show/hide each of the values.
How can I handle with this?
Can I do something like in the Application Layer:
public GetFamilyOutput GetFamily(GetFamilyInput input)
{
Family family = _familyRepository.GetFamily(input.Username);
FamilyConfiguration familyConfiguration = _familyConfigurationRepository.GetConfigurations(family.Id);
//ProcessConfiguration will set to null the properties that I cannot show
family.ProcessConfiguration(familyConfiguration);
return new GetFamilyOutput
{
//Map Family Object to the GetFamilyOutput
};
}
Note: The Family, DefaultMessage and FamilyConfiguration are domain objects created inside the Domain Layer.
What is your opinion?
Thanks :)
Edited:
Note: I liked all the answers below and I used a little of all :) (I can´t mark all answers as acceptable)
What your application service is doing in #1 is perfectly valid: it coordinates the workflow with very little to no business logic knowledge.
There are certainly few improvements that could be done however, for instance:
I do not see any transactions? The email should only be sent upon a successfully comitted transaction.
Sending the email could be seen as a side-effect of the family's approval. I suppose the business experts could have stated: "when a family is approved then notify interested parties by email". Therefore, it could be wise to publish a FamilyApproved domain event and move the email sending logic in an event handler.
Note that you want the handler to be called asynchronously only
after the domain event was persisted to disk and you want to persist
the event in the same transaction as the aggregate.
You could probably further abstract the mailing process into something like emailService.send(MessageTypes.FamilyApproved, family.getEmail()). The application service wouldn't have to know about default messages.
Repositories are usually exclusive to aggregate roots (AR), if DefaultMessage is not an AR then I'd consider naming the DefaultMessageRepository service differently.
As for #2, although authorization checks could be done in the domain, it is much more common to relieve the domain from such task and enforce permissions in the application layer. You could even have a dedicated Identity & Access supporting Bounded Context (BC).
"//ProcessConfiguration will set to null the properties that I cannot
show"
That solution wouldn't be so great (just like implementing the IFamilyProperty solution) because your domain model becomes polluted by technical authorization concerns. If you are looking to apply DDD then the model should be as faithful as possible to the Ubiquitous Language (UL) and I doubt IFamilyProperty is something your domain experts would mention or even understand. Allowing properties to become null would probably violate some invariants as well.
Another problem with such solution is that the domain model is rarely adapted for queries (it's built for commands), so it's often preferrable to bypass it entirely and favor going directly to the DB. Implementing authorizations in the domain would prevent you from doing that easily.
For at least these reasons, I think it is preferrable to implement authorization checks outside the domain. There your are free to use whatever implementation you want and suits your needs. For instance, I believe that stripping off values from a DTO could be legitimate.
I also was doubting if it's ok to place some logic to Application Service or not. But things got much cleaner once I read Vladimir Khorikov's Domain services vs Application services article. It states that
domain services hold domain logic whereas application services don’t.
and illustrates the idea by great examples. So in your cases I think it's totally fine to place these scenarios to Application Service as it doesn't contain domain logic.
Ad 1
I usually move that logic into domain layer - services.
So then the application layer just calls:
public ApproveFamilyOutput ApproveFamily(ApproveFamilyInput input)
{
var approveService = diContainer.Get<ApproveService>(); // Or correctly injected by constructor
var result = approveService.ApproveFamily(input);
// Convert to ouput
}
And domain service (AppproveService class) looks like:
public ApproveResult ApproveFamily(ApproveFamilyInput input)
{
var family = _familyRepository.GetFamily(input.Username);
family.Approve();
_familyRepository.Update(family);
bool isSaved = _familyRepository.Save();
if(isSaved)
_eventPublisher.Publish(family.raisedEvents);
// return result
}
To make it work (and following hexagonal/onion architecture), domain layer defines all interfaces for its dependencies (IFamilyRepository, IDefaultMessageRepository, etc) and application layer injects specific implementation into domain layer.
To make it clear:
1. domain layer is independent
2. domain objects are pure - consist of entities, value objects
3. domain objects don't call repositories, it is up to the domain service
4. domain objects raise events
5. unrelated logic is handled by events (event handlers) - for example sending emails, it follows open-closed principle
class FamilyApprovedHandler : IHandle<FamilyApprovedEvent>
{
private readonly IDefaultMessageRepository _defaultMessageRepository;
private readonly IEmailSender _emailSender;
private readonly IEmailProvider _emailProvider;
// ctor
public Task Handle(FamilyApprovedEvent event)
{
var defaultMessage = _defaultMessageRepository.GetDefaultMessage(MessageTypes.FamilyApproved);
var email = _emailProvider.Generate(event.Family, defaultMessage.Subject, defaultMessage.Message);
_emailSender.Send(email);
}
}
As for #1:
Theoretically, the application layer can do what you have described. However, I personally prefer to separate concerns further: there should be a persistence layer. In your case, a developer needs to know to:
Get the family from the repository.
Call the method to approve the family object.
Update the family back in the repository.
Persist the repository.
Handle any possible errors if there were persistence errors.
I would argue that 2-3-4 should be moved to a persistence layer, to make the code look like:
Family family = _familyRepository.GetFamily(input.Username);
family.Approve().Notify(_email);
This approach gives one more flexibility in how to handle errors and some business logic improvements. For example, you would not be sending an e-mail if you encounter persistence errors.
Of course, you'd need to have some additional types and extension methods implemented (for "Notify()" as an example).
Finally, I'd argue that e-mail service should be implemented using a repository pattern too (so you have two repositories) and have a persistence-level implementation. My point of view: anything persisted outside of the application requires repository & persistence implementation; e-mails are persisted outside of the application in user's mailbox.
As for #2:
I would strongly recommend against nullable properties and clearing them out. It gets really confusing really fast, very hard to unit-test and has a lot of "hidden" caveats. Instead, implement classes for your properties. For example:
public class UserPriviledge { //... your db-defined privileges }
public interface IFamilyProperty<T>
{
public string PropertyName { get; }
public T PropertyValue { get; }
public List<UserPriviledge> ReadPriviledges { get; }
public bool IsReadOnly { get; }
}
public class FamilyName : IFamilyProperty<string>
{
public static string PropertyName => "Name";
public string PropertyValue { get; }
public List<UserPriviledge> ReadPriviledges { get; }
public bool IsReadOnly { get; private set; }
public FamilyName(string familyName) {
this.PropertyValue = familyName;
this.ReadPriviledges.Add(someUserPrivilege);
this.IsReadOnly = false;
}
public void MakeReadOnly() {
this.IsReadOnly = true;
}
}
public class Family
{
public int Id { get; }
public List<IFamilyProperty> LimitedProperties { get; }
}
With this kind of implementation you can have the same kind of method that removes the values instead of obfuscating the value or applies even more complicated logic:
public void ApplyFamilyPermissions(Family family, UserEntity user)
{
foreach (var property in family.LimitedProperties) {
if (property.ReadPriviledges.Intersect(user.Priviledges).Any() == false) {
family.LimitedProperties.Remove(property);
} else if (property.IsReadOnly == false && HasPropertyWriteAccess(property, user) == false) {
property.MakeReadOnly();
}
}
}
Note: the code was not verified and I'm pretty sure has some syntax mistakes, but I believe it communicates the idea clearly.

LINQ to SQL and N-Tier layering

My experience has made me more accustomed to the following structure in my programs. Let's say it is a .NET WPF application. You create a WPF project, a Business Logic project (Class Library), a Data Access project (Class Library), and an Entities project (Class Library). The WPF project goes through the Business Logic Layer to the Data Access Layer. The Entities are lightweight DTOs and can flow freely from layer to layer.
My question is this. I like LINQ to SQL entities, except if I use it to create my entities, I not only wind up with a straight table to entities relationship, it also puts my Entities in my Data Access project and forces my UI project to have a reference to my Data Access project. Granted, I can make my DataContext internal (which I think it should be by default anyhow), except my DTOs are still in my Data Access project and it still forces my UI project to have a reference to my Data Access project.
Am I missing something here or is there another way to extricate my DTOs with LINQ to SQL or should I even care?
If we follow a Dependency inversion principle
High level modules should not depend upon low-level modules. Both should depend upon abstractions.
Abstractions should never depend upon details. Details should depend upon abstractions.
So in your case UI and Business logic should not depend upon Data access. Abstracted entities should never depend upon details of LINQ to SQL
Then we start design our application from high level layers
1 Create Project of entities abstractions
public interface ICustomer
{
int Id { get; set; }
}
2 Create Project business logic abstractions used by UI project
public interface ICustomerService
{
List<ICustomer> LoadTop50();
}
3 Create UI project
3.1 Create UI logic which use ICustomer and ICustomerService for showing person information
Notice: UI depends only on abstractions and have no knowledge about other layers.
4 Create Business project
4.1 Create DataAccess abstraction for fetching data
namespace Business.DataAccessAbstractions
{
public interface ICustomerDataAccess
{
List<ICustomer> Load(int topAmount);
}
}
4.2 Implement ICustomerService which use abstractions of ICustomerDataAccess
public class CustomerService : ICustomerService
{
private DataAccessAbstractions.ICustomerDataAccess _dataAccess;
public CustomerService(DataAccessAbstractions.ICustomerDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public IEnumerable<ICustomer> LoadTop50()
{
const int TOP_NUMBER = 50;
return _dataAccess.Load(TOP_NUMBER);
}
}
Notice: Business project create abstractions for data access. And implement abstractions, which UI will use for showing data.
5 Create DataAccess project
5.1 Create entities with LINQ to SQL.
5.2 Implement Business.DataAccessAbstractions.ICustomerDataAccess interface.
5.2.1 Make entities, generated by LINQ to SQL, implement ICustomer
[Table(Name="dbo.Customer")]
public partial class Customer : INotifyPropertyChanging,
INotifyPropertyChanged,
ICustomer
{
private int _Id;
[Column(Storage="_Id",
AutoSync=AutoSync.OnInsert,
DbType="Int NOT NULL IDENTITY",
IsPrimaryKey=true,
IsDbGenerated=true)]
public int Id
{
get
{
return this._Id;
}
set
{
if ((this._Id != value))
{
this.OnIDChanging(value);
this.SendPropertyChanging();
this._Id = value;
this.SendPropertyChanged("Id");
this.OnIDChanged();
}
}
}
}
You need only add ICustomer to the list of implemented interfaces. Or create/generate some "mapping logic" which convert entities generated by LINQ to SQL to the instances which will impelement ICustomer. I found that adding ICustomer was easiest way for this sample.
Notice: DataAccess project have dependencies only on abstractions which is implemented by using LINQ to SQL
6 Create Main project which will compound all dependencies together and launch your UI.
Notice: This project will have all references needed for your application to work properly.
Summary
With this approach you UI will not depend on details of LINQ to SQL.
With this approach you can freely modify your implementation of DataAccess until modifications will not break high level abstractions.
Of course if you decide to add new data field for Customer, which you want use in UI, then you need to modify whole chain of dependencies.

Domain Logic leaking into Queries in MVC.NET application using DDD

I am trying to implement a query to fetch some projection of data to MVC view from DB managed by domain model.
I've read that MVC controllers returning static views should request DTOs from Query handlers or so-called read model repositories rather than using aggregate root repositories returning full fledged domain objects. This way we maximize performance (optimizing queries for needed data) and reduce a risk of domain model misuse (we can't accidentally change model with DTOs).
The problem is that some DTO properties can't directly map to DB Table field and may be populated based on some business rule or be a result of some condition that is not implicitly stated in DB. That means that the query acts upon some logic leaking from domain. I heard that it's not right and that queries should directly filter, order, project and aggregate data from DB tables (using linq queries and EF in my case).
I envision 2 solutions so far:
1) Read model repositories internally query full domain model objects, use them to populate DTO properties (importantly those requiring some business logic from them to use). Here we don't gain performance benefits as we act upon instantiated domain models.
2) The other solution is cache all ever required data in DB through probably domain repositories (dealing with aggregate roots) so queries act upon data fields (with cached values) without addressing to domain logic. The consistency of the cached data then will be maintained by domain repositories and that results in some overhead as well.
Examples:
1) business rule can be as simple as string representation of certain objects or data (across the system) i.e. formatting;
2) Business rule can be calculated field returning bool as in the simple domain model below:
// first aggregate root
public class AssignedForm
{
public int Id {get;set}
public string FormName {get;set}
public ICollection<FormRevision> FormRevisions {get;set}
public bool HasTrackingInformation
{
get
{
return FormRevisions.Any(
fr=> fr.RevisionType==ERevisionType.DiffCopy
&& fr.FormRevisionItems.Any)
}
}
public void CreateNextRevision()
{
if(HasTrackingInformation)
{
.......
}
.......
}
}
public enum ERevisionType { FullCopy=0,DiffCopy=1 }
public class FormRevision
{
public int Id {get;set}
public ERevisionType RevisionType {get;set}
public ICollection<FormRevisionItem> FormRevisionItems {get;set}
}
And then we have a read model repository, say IFormTrackingInfoReader returning collection of objects
public class FormTrackingInfo
{
public int AssignedFormId {get;set}
public int AssignedFormName {get;set}
public bool HasTrackingInformation {get;set}
}
The question is how to implement IFormTrackingInfoReader and populate HasTrackingInformation property sticking to DRY principle and without domain leaking into query. I saw people just return domain objects and use mapping to populate view model. Probably this is way to go. Thank you for your help.
I don't like solution 1, the domain model is not persistent ignorant.
Personally, I prefer solution2. But the "ever required data" may be a problem. If new query requirement emerges, perhaps you'll need some data migration(I heard events replaying will do the trick when using event sourcing). So I'm thinking is there a hybrid solution: Use value objects to implement the derivations. And we can create new value object instances with dto.
public class SomeDto {
public String getSomeDerivation() {
return new ValueObject(some data in this dto).someDerivation();
}
}
In this case, I think domain logic is protected and seperated from persistence. But I haven't tried this in real projects.
UPDATE1:
The hybrid solution does not fit your particular FormTrackingInfo case, but your solution two does. One example is (sorry, I'm not a .net guy, in Java)
public class CustomerReadModel {
private String phoneNumber;
private String ....//other properties
public String getPhoneNumber() {
return phoneNumber;
}
public String getAreaCode() {
return new PhoneNumber(this.phoneNumber).getAreaCode();//PhoneNumber is a value object.
}
}
But like I said, I haven't tried it in real projects, I think it's at most an interim solution when the cached data is not ready.

Managing persistence in DDD

Let's say that I want to create a blog application with these two simple persistence classes used with EF Code First or NHibernate and returned from repository layer:
public class PostPersistence
{
public int Id { get; set; }
public string Text { get; set; }
public IList<LikePersistence> Likes { get; set; }
}
public class LikePersistence
{
public int Id { get; set; }
//... some other properties
}
I can't figure out a clean way to map my persistence models to domain models. I'd like my Post domain model interface to look something like this:
public interface IPost
{
int Id { get; }
string Text { get; set; }
public IEnumerable<ILike> Likes { get; }
void Like();
}
Now how would an implementation underneath look like? Maybe something like this:
public class Post : IPost
{
private readonly PostPersistence _postPersistence;
private readonly INotificationService _notificationService;
public int Id
{
get { return _postPersistence.Id }
}
public string Text
{
get { return _postPersistence.Text; }
set { _postPersistence.Text = value; }
}
public IEnumerable<ILike> Likes
{
//this seems really out of place
return _postPersistence.Likes.Select(likePersistence => new Like(likePersistence ));
}
public Post(PostPersistence postPersistence, INotificationService notificationService)
{
_postPersistence = postPersistence;
_notificationService = notificationService;
}
public void Like()
{
_postPersistence.Likes.Add(new LikePersistence());
_notificationService.NotifyPostLiked(Id);
}
}
I've spent some time reading about DDD but most examples were theoretical or used same ORM classes in domain layer. My solution seems to be really ugly, because in fact domain models are just wrappers around ORM classes and it doens't seem to be a domain-centric approach. Also the way IEnumerable<ILike> Likes is implemented bothers me because it won't benefit from LINQ to SQL. What are other (concrete!) options to create domain objects with a more transparent persistence implementation?
One of the goals of persistence in DDD is persistence ignorance which is what you seem to be striving for to some extent. One of the issues that I see with your code samples is that you have your entities implementing interfaces and referencing repositories and services. In DDD, entities should not implement interfaces which are just abstractions of itself and have instance dependencies on repositories or services. If a specific behavior on an entity requires a service, pass that service directly into the corresponding method. Otherwise, all interactions with services and repositories should be done outside of the entity; typically in an application service. The application service orchestrates between repositories and services in order to invoke behaviors on domain entities. As a result, entities don't need to references services or repositories directly - all they have is some state and behavior which modifies that state and maintains its integrity. The job of the ORM then is to map this state to table(s) in a relational database. ORMs such as NHibernate allow you to attain a relatively large degree of persistence ignorance.
UPDATES
Still I don't want to expose method with an INotificationService as a
parameter, because this service should be internal, layer above don't
need to know about it.
In your current implementation of the Post class the INotificationService has the same or greater visibility as the class. If the INotificationService is implemented in an infrastructure layer, it already has to have sufficient visibility. Take a look at hexagonal architecture for an overview of layering in modern architectures.
As a side note, functionality associated with notifications can often be placed into handlers for domain events. This is a powerful technique for attaining a great degree of decoupling.
And with separate DTO and domain classes how would you solve
persistence synchronization problem when domain object doesn't know
about its underlying DTO? How to track changes?
A DTO and corresponding domain classes exist for very different reasons. The purpose of the DTO is to carry data across system boundaries. DTOs are not in a one-one correspondence with domain objects - they can represent part of the domain object or a change to the domain object. One way to track changes would be to have a DTO be explicit about the changes it contains. For example, suppose you have a UI screen that allows editing of a Post. That screen can capture all the changes made and send those changes in a command (DTO) to a service. The service would load up the appropriate Post entity and apply the changes specified by the command.
I think you need to do a bit more research, see all the options and decide if it is really worth the hassle to go for a full DDD implementation, i ve been there myself the last few days so i ll tell you my experience.
EF Code first is quite promising but there are quite a few issues with it, i have an entry here for this
Entity Framework and Domain Driven Design. With EF your domain models can be persisted by EF without you having to create a separate "persistence" class. You can use POCO (plain old objects) and get a simple application up and running but as i said to me it s not fully mature yet.
If you use LINQ to SQL then the most common approach would be to manually map a "data transfer object" to a business object. Doing it manually can be tough for a big application so check for a tool like Automapper. Alternatively you can simply wrap the DTO in a business object like
public class Post
{
PostPersistence Post { get; set;}
public IList<LikePersistence> Likes { get; set; }
.....
}
NHibernate: Not sure, havent used it for a long time.
My feeling for this (and this is just an opinion, i may be wrong) is that you ll always have to make compromises and you ll not find a perfect solution out there. If you give EF a couple more years it may get there. I think an approach that maps DTOs to DDD objects is probably the most flexible so looking for an automapping tool may be worth your time. If you want to keep it simple, my favourite would be some simple wrappers around DTOs when required.

Entity Framework business object transformation

I am trying to create a small personal project which uses EF to handle data access. My project architecture has a UI layer, a service layer, a business layer and a data access layer. The EF is contained within the DAL. I don't think it's right to then make reference to my DAL, from my UI. So I want to create custom classes for 'business objects' which is shared between all my layers.
Example: I have a User table. EF creates a User entity. I have a method to maybe GetListOfUsers(). That, in the presentation, shouldn't reply on a List, as the UI then has a direct link to the DAL. I need to maybe have a method exposed in the DAL to maybe be something like:
List<MyUserObject> GetListOfUsers();
That would then call my internal method which would GetListOfUsers which returns a list of user entities, and then transforms them into my MyUserObejcts, which is then passed back through the layers to my UI.
Is that correct design? I don't feel the UI, or business layer for that matter, should have any knowledge of the entity framework.
What this may mean, though, is maybe I need a 'Transformation layer' between my DAL and my Business layer, which transforms my entities into my custom objects?
Edit:
Here is an example of what I am doing:
I have a data access project, which will contain the Entity Framework. In this project, I will have a method to get me a list of states.
public class DataAccessor
{
taskerEntities te = new taskerEntities();
public List<StateObject> GetStates()
{
var transformer = new Transformer();
var items = (from s in te.r_state select s).ToList();
var states = new List<StateObject>();
foreach (var rState in items)
{
var s = transformer.State(rState);
states.Add(s);
}
return states;
}
}
My UI/Business/Service projects mustn't know about entity framework objects. It, instead, must know about my custom built State objects. So, I have a Shared Library project, containing my custom built objects:
namespace SharedLib
{
public class StateObject
{
public int stateId { get; set; }
public string description { get; set; }
public Boolean isDefault { get; set; }
}
}
So, my DAL get's the items into a list of Entity objects, and then I pass them through my transformation method, to make them into custom buily objects. The tranformation takes an EF object, and outputs a custom object.
public class Transformer
{
public StateObject State (r_state state)
{
var s = new StateObject
{
description = state.description,
isDefault = state.is_default,
stateId = state.state_id
};
return s;
}
}
This seems to work. But is it a valid pattern?
So, at some point, your UI will have to work with the data and business objects that you have. It's a fact of life. You could try to abstract farther, but that would only succeed in the interaction being deferred elsewhere.
I agree that business processes should stand alone from the UI. I also agree that your UI should not directly act with how you access your data. What have you suggested (something along the lines of "GetListOfUsers()") is known as the Repository Pattern.
The purpose of the repository pattern is to:
separate the logic that retrieves the data and maps it to the entity
model from the business logic that acts on the model. The business
logic should be agnostic to the type of data that comprises the data
source layer
My recommendation is to use the Repository Pattern to hide HOW you're accessing your data (and, allow a better separation of concerns) and just be concerned with the fact that you "just want a list of users" or you "just want to calculate the sum of all time sheets" or whatever it is that you want your application to actually focus on. Read the link for a more detailed description.
First, do you really need all that layers in your 'small personal project'?
Second, I think your suggested architecture is a bit unclear.
If I get you right, you want to decouple your UI from your DAL. For that purpose you can for example extract interface of MyUserObject (defined in DAL obviously) class, lets call it IMyUserObject, and instead of referencing DAL from UI, reference some abstract project, where all types are data-agnostic. Also, I suggest that you'd have some service layer which would provide your presentation layer (UI) with concrete objects. If you utilize MVC you can have a link to services from your controller class. Service layer in turn can use Repository or some other technique to deal with DAL (it depends on the complexity you choose)
Considering transformation layer, I think people deal with mapping from one type to another when they have one simple model (DTO) to communicate with DB, another one - domain model, that deals with all the subtleties of business logic, and another one - presentational model, that is suited best to let user interact with. Such layering separates concerns to good measure, making each task simpler, but making app more complicated in general.
So you may end having MyUserObjectDTO, MyUserObject and MyUserObjectView and some mapping or transformation btw them.

Categories

Resources