Reputation: 9828
I am new to Entity framework and am getting confused about how to implement Business Logic.
I am using the Code First approach and have generated my POCOs. I have them in a separate project so they can be used in multiple projects.
I would like to know how i can implement business logic for an object, that is checked when i try to save an item to the database. For example, if I define a rule that MyObject cannot be saved unless a name is entered, how can i do this?
Example simple POCO
public class MyObject() {
public String name { get; set; };
public MyObject() {}
}
Obviously i have many objects, and each object has different business rules.
I am coming from a Csla (http://www.lhotka.net/cslanet/) business framework background, where you define a business object, which has a Save method. upon calling Save, the framework runs the ValidationRules and thus determines whether a call to the database is needed.
I would like something like this, using Entity Framework. Code example would be great, or references to reading material. Thanks
Upvotes: 4
Views: 3406
Reputation: 911
I generally build a Service Layer in my application to handle business logic, which talks to my Data Access Layer to persist any data.
public class JobService : IJobService
{
private readonly IJobRepository _jobRepository;
public JobService(IJobRepository jobRepository)
{
_jobRepository = jobRepository;
}
public IEnumerable<Job> GetAllJobs()
{
return _jobRepository.All().OrderBy(x => x.Name);
}
public Job GetJobById(Guid Id)
{
return _jobRepository.FindBy(x => x.Id == Id);
}
public void UpdateJob(Job job, User user)
{
job.LastUpdatedDate = DateTime.Now;
job.LastUpdatedBy = user;
_jobRepository.Update(job);
}
public void DeleteJob(Job job)
{
_jobRepository.Delete(job);
}
public void SaveJob(Job job, User user)
{
job.CreatedDate = DateTime.Now;
job.CreatedBy = user;
_jobRepository.Insert(job);
}
}
Your Services can be as complicated as you want while still abstracting away your Data Access Layer. I wouldn't add any methods to your POCO classes as that defeats the purpose of what a POCO class is. Services are also a great place to validate business rules as well. Although I have not provided an example of that, validation could easily be added to your service methods.
EDIT
The architecture I generally use when writing larger applications requires contracts to define your data access layer. The reason we use interfaces to define our class structure is so that we can implement them differently without having to change any code that uses those classes. For example, you may implement your repository pattern using EF, but later may find that you want to use NHibernate. To make that change you'd only have to change the implementation of the repository and not your code that actually uses the repository.
My repository contract usually looks like:
/// <summary>
/// This interface is implemented by all repositories to ensure implementation of fixed methods.
/// </summary>
/// <typeparam name="TEntity">Main Entity type this repository works on</typeparam>
/// <typeparam name="TKey">Primary key type of the entity</typeparam>
public interface IRepository<TKey, TEntity> : IRepository where TEntity : class, IEntity<TKey>
{
/// <summary>
/// Inserts a new entity.
/// </summary>
/// <param name="entity">Entity to insert</param>
TEntity Insert(TEntity entity);
/// <summary>
/// Inserts multiple entities.
/// </summary>
/// <param name="entities">Entities to insert</param>
IEnumerable<TEntity> Insert(IEnumerable<TEntity> entities);
/// <summary>
/// Updates an existing entity.
/// </summary>
/// <param name="entity">Entity</param>
TEntity Update(TEntity entity);
/// <summary>
/// Updates or saves an entity
/// </summary>
/// <param name="entity">Entity</param>
TEntity SaveOrUpdate(TEntity entity);
/// <summary>
/// Deletes an entity.
/// </summary>
/// <param name="id">Id of the entity</param>
bool Delete(TKey id);
/// <summary>
/// Deletes an entity.
/// </summary>
/// <param name="entity">Entity to be deleted</param>
bool Delete(TEntity entity);
/// <summary>
/// Deletes an entity.
/// </summary>
/// <param name="entities">Entities to be deleted</param>
bool Delete(IEnumerable<TEntity> entities);
/// <summary>
/// Used to get an IQueryable that is used to retrieve entities from entire table.
/// </summary>
/// <returns>IQueryable to be used to select entities from database</returns>
IQueryable<TEntity> All();
/// <summary>
/// Gets an entity.
/// </summary>
/// <param name="expression">LINQ expression used to evaluate and find an entity</param>
/// <returns>Entity</returns>
TEntity FindBy(Expression<Func<TEntity, bool>> expression);
/// <summary>
/// Used to get an IQueryable that is used to retrieve entities from evaluated LINQ expression.
/// </summary>
/// <param name="expression">LINQ expression used to evaluate and find entities</param>
/// <returns>IQueryable to be used to select entities from database</returns>
IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression);
/// <summary>
/// Gets an entity.
/// </summary>
/// <param name="id">Primary key of the entity to get</param>
/// <returns>Entity</returns>
TEntity FindBy(TKey id);
}
and then IJobRepository:
// We create separate repositories inheriting from IRepository in case we need specific repository methods for that entity
public interface IJobRepository : IRepository<Guid, Job>
{
}
How you implement the repository is up to you, but generally for EF you'd pass your repository a DbSet or DbContext and perform actions on that.
Your service contracts will depend on your business logic. Some entities you may only ever need to read from persistent storage. Others you will have to make service methods to validate/insert/manipulate/etc.
This design pattern works best when you're using Inversion of Control (IoC) to inject implementations of those contracts as constructor parameters. I generally use Castle Windsor, but there are many IoC dependency injection frameworks out there.
Upvotes: 4