ASP.NET MVC分層架構(8)-BaseModel and BaseService
介紹
分層架構到這裡後,會發現有些地方明明是一樣的功能,卻還要重複編寫,像是CRUD這種功能,在這要說明如何將CRUD的部分抽離出來,使程式簡單化,不用寫重複的功能。
BaseModel
在SQLModel專案的Models資料夾下,新增BaseModel類別,裡面的內容是通常每個表都會使用的欄位,程式如下:
public abstract class BaseModel
{
public DateTime CreateDate { get; set; }
public DateTime ModifyDate { get; set; }
public string CreatorId { get; set; }
[ForeignKey("CreatorId")]
public virtual ApplicationUser Creator { get; set; }
public string ModifyId { get; set; }
[ForeignKey("ModifyId")]
public virtual ApplicationUser Modify { get; set; }
}
繼承BaseModel
在Project Model裡加入繼承BaseModel,在每次有新增Project的時候也會連BaseModel的內容一起新增,程式如下:
public class Project : BaseModel
{
[Key]
[Required]
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Structure> Structure { get; set; }
}
Structure一樣也繼承BaseModel,記得要在下指令Add-Migration,再下Update-Database就新增好BaseModel了。
修改Repository
修改SQLModel專案的IRepository和GenericRepository,程式如下:
IRepository.cspublic interface IRepository<TEntity>
{
IUnitOfWork UnitOfWork { get; set; }
Guid Create(TEntity entity);
void Update(TEntity entity);
Guid Delete(TEntity entity);
IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> GetAll();
TEntity GetById(Guid id);
}
public class GenericRepository<TEntity> : IRepository<TEntity>
where TEntity : BaseModel
{
public IDbSet<TEntity> DbSet { get; set; }
public DbContext DbContext { get; set; }
public IUnitOfWork UnitOfWork { get; set; }
public GenericRepository(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
this.DbContext = unitOfWork.Context;
this.DbSet = DbContext.Set<TEntity>();
}
public virtual Guid Create(TEntity entity)
{
dynamic obj = DbSet.Add(entity);
return obj.Id;
}
public void Update(TEntity entity)
{
DbSet.Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
DbContext.Entry(entity).Property(x => x.CreateDate).IsModified = false;
DbContext.Entry(entity).Property(x => x.CreatorId).IsModified = false;
}
public virtual Guid Delete(TEntity entity)
{
if (DbContext.Entry(entity).State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dynamic obj = DbSet.Remove(entity);
return obj.Id;
}
public virtual IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public virtual IQueryable<TEntity> GetAll()
{
return DbSet;
}
public virtual TEntity GetById(Guid id)
{
return DbSet.Find(id);
}
}
BaseService
在Service專案下,新增BaseService,在Nuget下載Microsoft.AspNet.WebApi.Client和Microsoft.AspNet.Identity.Core,Service會使用到這些參考,我們將BaseService利用泛型寫成可以傳入任何的Model,另外在這裡有用到IsNotEmptyOrNull是自己寫的一個StringHelper類別裡的方法,程式如下:
IBaseService.cspublic interface IBaseService<TEntity>
{
Guid Create(TEntity entity);
bool Update(TEntity entity);
bool UpdateOnly(TEntity entity);
bool Delete(Guid id);
IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> GetAll();
TEntity GetById(Guid id);
}
public abstract class BaseService<TEntity> : IBaseService<TEntity> where TEntity : BaseModel
{
private readonly IUnitOfWork _unitOfWork;
protected IRepository<TEntity> _repository { get; set; }
public BaseService(IUnitOfWork unitOfWork, IRepository<TEntity> repository)
{
this._unitOfWork = unitOfWork;
this._repository = repository;
}
public virtual Guid Create(TEntity entity)
{
string userId = HttpContext.Current.User.Identity.GetUserId();
entity.CreatorId = entity.CreatorId.IsNotEmptyOrNull() ? entity.CreatorId : userId;
entity.CreateDate = DateTime.Now;
entity.ModifyId = userId;
entity.ModifyDate = DateTime.Now;
var result = _repository.Create(entity);
_repository.UnitOfWork.SaveChange();
return result;
}
public virtual bool Update(TEntity entity)
{
bool result = false;
if (null != entity)
{
entity.ModifyId = HttpContext.Current.User.Identity.GetUserId();
entity.ModifyDate = DateTime.Now;
_repository.Update(entity);
_unitOfWork.SaveChange();
result = true;
}
return result;
}
public virtual bool UpdateOnly(TEntity entity)
{
bool result = false;
if (null != entity)
{
_repository.Update(entity);
_unitOfWork.SaveChange();
result = true;
}
return result;
}
public virtual bool Delete(Guid id)
{
var entity = _repository.GetById(id);
var result = _repository.Delete(entity);
_repository.UnitOfWork.SaveChange();
return result == id;
}
public virtual IQueryable<TEntity> GetAll()
{
var result = _repository.GetAll();
return result;
}
public virtual TEntity GetById(Guid id)
{
var result = _repository.GetById(id);
return result;
}
public virtual IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate)
{
return _repository.FindBy(predicate);
}
}
public static class StringHelper
{
public static bool IsEmptyOrNull(this string input)
{
if (input == null || input.Equals(""))
{
return true;
}
else
{
return false;
}
}
public static bool IsNotEmptyOrNull(this string input)
{
if (input == null || input.Equals(""))
{
return false;
}
else
{
return true;
}
}
}
修改ProjectService
接著要修改IProjectService和ProjectService,要繼承BaseService並在泛型裡加上使用的Model,繼承以後就不需要在每個Service寫CRUD這些重複的功能,程式如下:
IProjectService.cspublic interface IProjectService : IBaseService<Project>
{
}
public class ProjectService : BaseService<Project>, IProjectService
{
public ProjectService(IUnitOfWork unitOfWork, IRepository<Project> repository)
: base(unitOfWork, repository)
{ }
}
StructureService就跟ProjectService差不多,去做修改就好了。都修改好之後,就可以執行了。到這裡會發現不用在每次新增新的Model後,在新的Service上還要寫CRUD這些功能了,只需要繼承BaseService就可以有這些功能,是不是方便很多!