我是Entity框架的新手,对于如何实现业务逻辑感到困惑。
我正在使用Code First方法并生成了我的POCO。我把它们放在一个单独的项目中,这样它们就可以用在多个项目中。
我想知道如何为对象实现业务逻辑,当我尝试将项目保存到数据库时会检查该逻辑。例如,如果我定义一个规则,除非输入名称,否则无法保存MyObject,我该怎么办呢?
示例简单POCO
public class MyObject() {
public String name { get; set; };
public MyObject() {}
}
显然我有很多对象,每个对象都有不同的业务规则。
我来自Csla(http://www.lhotka.net/cslanet/)业务框架背景,您可以在其中定义一个具有Save方法的业务对象。在调用Save时,框架运行ValidationRules,从而确定是否需要调用数据库。
我想使用Entity Framework这样的东西。代码示例很棒,或者对阅读材料的引用。感谢
答案 0 :(得分:4)
我通常在我的应用程序中构建一个服务层来处理业务逻辑,该逻辑与我的数据访问层对话以保留任何数据。
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);
}
}
您的服务可能会像您想要的那样复杂,同时仍然会抽象出您的数据访问层。我不会为你的POCO课程添加任何方法,因为这会破坏POCO课程的目的。服务也是验证业务规则的好地方。虽然我没有提供相关示例,但可以轻松地将验证添加到您的服务方法中。
修改强>
我在编写较大的应用程序时通常使用的架构需要合同来定义您的数据访问层。我们使用接口来定义类结构的原因是我们可以以不同方式实现它们,而无需更改使用这些类的任何代码。例如,您可以使用EF实现存储库模式,但稍后可能会发现您要使用NHibernate。要进行更改,您只需更改存储库的实现,而不是实际使用存储库的代码。
我的存储库合同通常如下:
/// <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);
}
然后是IJobRepository:
// We create separate repositories inheriting from IRepository in case we need specific repository methods for that entity
public interface IJobRepository : IRepository<Guid, Job>
{
}
如何实现存储库取决于您,但通常对于EF,您将向存储库传递DbSet或DbContext并对其执行操作。
您的服务合同将取决于您的业务逻辑。您可能只需要从持久存储中读取的某些实体。其他人则必须提供服务方法来验证/插入/操纵/等。
当您使用Inversion of Control(IoC)将这些契约的实现注入构造函数参数时,此设计模式最有效。我通常使用Castle Windsor,但那里有许多IoC依赖注入框架。