以前咱們系統學習了EntityFramework,我的以爲有些東西不能學了就算完了,必需要學以至用,在Web API上也少不了增(C)、刪(D)、改(U)、查(R)。鑑於此,咱們經過EF來實現Web API上的增刪改查。sql
咱們創建一個Core(核心類庫),裏面存放有關EF的完成封裝。數據庫
public class BaseEntity<T> { public T Id { get; set; } }
public interface IRepository<TEntity> where TEntity : class { /// <summary> /// 得到數據列表 /// </summary> /// <returns></returns> IQueryable<TEntity> GetList(); /// <summary> /// 經過id得到實體 /// </summary> /// <param name="id"></param> /// <returns></returns> TEntity GetById(object id); /// <summary> /// 添加實體 /// </summary> /// <param name="entity"></param> int Insert(TEntity entity); /// <summary> /// 添加實體集合 /// </summary> /// <param name="entities"></param> int Insert(IEnumerable<TEntity> entities); /// <summary> /// 刪除實體 /// </summary> /// <param name="entity"></param> int Delete(TEntity entity); /// <summary> /// 根據條件刪除實體 /// </summary> /// <param name="entities"></param> int DeleteByRequirement(Expression<Func<TEntity, bool>> func); /// <summary> /// 更新實體 /// </summary> /// <param name="entity"></param> int Update(TEntity entity); /// <summary> /// 更新實體集合 /// </summary> /// <param name="entities"></param> int Update(IEnumerable<TEntity> entities); }
public class RepositoryService<TEntity> : IRepository<TEntity> where TEntity : class { private IDbContext Context; private bool IsNoTracking; /// <summary> /// 獲取實體集合 /// </summary> private IDbSet<TEntity> Entities { get { return this.Context.Set<TEntity>(); } } private DbEntityEntry Entry(TEntity entity) { return this.Context.Entry<TEntity>(entity); } public RepositoryService(IDbContext context, bool isNoTracking) { this.Context = context; this.IsNoTracking = isNoTracking; } /// <summary> /// 獲取全部數據 /// </summary> /// <returns></returns> public IQueryable<TEntity> GetList() { if (!IsNoTracking) return this.Entities.AsQueryable(); else return this.Entities.AsNoTracking().AsQueryable(); } /// <summary> /// 經過id獲取實體 /// </summary> /// <param name="id"></param> /// <returns></returns> public TEntity GetById(object id) { return Entities.Find(id); } /// <summary> /// 添加實體 /// </summary> /// <param name="entity"></param> public int Insert(TEntity entity) { Entities.Add(entity); return this.Context.SaveChanges(); } public int Insert(IEnumerable<TEntity> entities) { if (entities == null) throw new ArgumentNullException("entities"); foreach (var entity in entities) { Entities.Add(entity); } return this.Context.SaveChanges(); } /// <summary> /// 刪除實體 /// </summary> /// <param name="entity"></param> public int Delete(TEntity entity) { if (!IsNoTracking) this.Entities.Remove(entity); else this.Entities.Attach(entity); this.Entities.Remove(entity); return this.Context.SaveChanges(); } public int DeleteByRequirement(Expression<Func<TEntity, bool>> func) { var list = GetList().Where(func).ToList(); list.ForEach(e => { if (!IsNoTracking) this.Entities.Remove(e); else this.Entities.Attach(e); this.Entities.Remove(e); }); return this.Context.SaveChanges(); } /// <summary> /// 更新實體 /// </summary> /// <param name="entity"></param> public int Update(TEntity entity) { if (!IsNoTracking) return this.Context.SaveChanges(); else this.Context.Entry(entity).State = EntityState.Modified; return this.Context.SaveChanges(); } public int Update(IEnumerable<TEntity> entities) { if (entities == null) throw new ArgumentNullException("enetities"); if (!IsNoTracking) return this.Context.SaveChanges(); else foreach (var t in entities) { this.Context.Entry(t).State = EntityState.Modified; } return this.Context.SaveChanges(); } /// <summary> /// 釋放資源 /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (Context != null) { this.Context.Dispose(); this.Context = null; } } } }
public interface IDbContext { /// <summary> /// 得到實體集合 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <returns></returns> IDbSet<TEntity> Set<TEntity>() where TEntity : class; /// <summary> /// 執行存儲過程 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="commandText"></param> /// <param name="parameters"></param> /// <returns></returns> IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : class; /// <summary> /// 執行SQL語句查詢 /// </summary> /// <typeparam name="TElement"></typeparam> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters); DbEntityEntry Entry<TEntity>(TEntity entity) where TEntity : class; /// <summary> /// 保存數據 /// </summary> /// <returns></returns> int SaveChanges(); /// <summary> /// 變動追蹤代碼 /// </summary> bool ProxyCreationEnabled { get; set; } /// <summary> /// DetectChanges方法自動調用 /// </summary> bool AutoDetectChangesEnabled { get; set; } /// <summary> /// 調用Dispose方法 /// </summary> void Dispose(); }
public class EFDbContext : DbContext, IDbContext { public EFDbContext(string connectionString) : base(connectionString) { } static EFDbContext() { Database.SetInitializer<EFDbContext>(new DropCreateDatabaseIfModelChanges<EFDbContext>()); } /// <summary> /// 一次性加載全部映射 /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { var typesToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !String.IsNullOrEmpty(type.Namespace)) .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } base.OnModelCreating(modelBuilder); } /// <summary> /// 得到實體集合 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <returns></returns> public new IDbSet<TEntity> Set<TEntity>() where TEntity : class { return base.Set<TEntity>(); } /// <summary> /// 實體狀態 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="entity"></param> /// <returns></returns> public new DbEntityEntry Entry<TEntity>(TEntity entity) where TEntity : class { return base.Entry<TEntity>(entity); } /// <summary> /// 執行存儲過程 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="commandText"></param> /// <param name="parameters"></param> /// <returns></returns> public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : class { if (parameters != null && parameters.Length > 0) { for (int i = 0; i <= parameters.Length - 1; i++) { var p = parameters[i] as DbParameter; if (p == null) throw new Exception("Not support parameter type"); commandText += i == 0 ? " " : ", "; commandText += "@" + p.ParameterName; if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output) { commandText += " output"; } } } var result = this.Database.SqlQuery<TEntity>(commandText, parameters).ToList(); bool acd = this.Configuration.AutoDetectChangesEnabled; try { this.Configuration.AutoDetectChangesEnabled = false; for (int i = 0; i < result.Count; i++) result[i] = this.Set<TEntity>().Attach(result[i]); } finally { this.Configuration.AutoDetectChangesEnabled = acd; } return result; } /// <summary> /// SQL語句查詢 /// </summary> /// <typeparam name="TElement"></typeparam> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters) { return this.Database.SqlQuery<TElement>(sql, parameters); } /// <summary> /// 當查詢或者獲取值時是否啓動建立代理 /// </summary> public virtual bool ProxyCreationEnabled { get { return this.Configuration.ProxyCreationEnabled; } set { this.Configuration.ProxyCreationEnabled = value; } } /// <summary> /// 當查詢或者獲取值時指定是否開啓自動調用DetectChanges方法 /// </summary> public virtual bool AutoDetectChangesEnabled { get { return this.Configuration.AutoDetectChangesEnabled; } set { this.Configuration.AutoDetectChangesEnabled = value; } } }
以上就是對利用EntityFramework來實現基本操做的完整封裝。接下來就是相關類以及映射(場景:一個Student對應一個Flower,而一個Flower對應多個Student)ide
public class Student : BaseEntity<int> { public string Name { get; set; } public int FlowerId { get; set; } public virtual Flower Flower { get; set; } }
public class Flower : BaseEntity<int> { public string Remark { get; set; } public virtual ICollection<Student> Students { get; set; } }
public class StudentMap:EntityTypeConfiguration<Student> { public StudentMap() { ToTable("Student"); HasKey(p => p.Id); Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); HasRequired(p => p.Flower).WithMany(p => p.Students).HasForeignKey(p => p.FlowerId); } } public class FlowerMap:EntityTypeConfiguration<Flower> { public FlowerMap() { ToTable("Flower"); HasKey(p => p.Id); Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); } }
接下來就是Web API控制器中執行增、刪等操做,咱們建立一個StudentController控制器,而後首先建立倉儲服務。(執行Action方法,依據默認約定,未添加特性)性能
public IRepository<Student> _repository; public EFDbContext _ctx; public StudentController() { _ctx = new EFDbContext("DBByConnectionString"); _repository = new RepositoryService<Student>(_ctx, true); //關閉局部變動追蹤 }
public IEnumerable<Student> GetAllStudent() { return _repository.GetList().Select(d => new Student { Name = d.Name, Flower = d.Flower, Id = d.Id }).ToList(); }
當執行此查詢操做時卻出錯了,真遺憾:學習
上述修改以下便可:ui
return _repository.GetList().ToList().Select(d => new Student { Name = d.Name, Flower = d.Flower, Id = d.Id }).ToList();
在此感謝園友(_天光雲影)給出的解決方案,在GetList以後利用 Linq 進行Select,最後進行ToList便可!!!this
public Student GetStudentById(int id) { var student = _repository.GetById(id); if (student == null) throw new HttpResponseException(HttpStatusCode.NotFound); else return student; } //添加操做(HttpPost) public HttpResponseMessage PostStudent(Student stu) { var insertStudent = _repository.Insert(stu); var response = Request.CreateResponse<Student>(HttpStatusCode.Created, stu); string uri = Url.Link("DefaultApi", new { id = stu.Id }); response.Headers.Location = new Uri(uri); return response; } //更新操做(HttpPut) public void PutStudent(int id, Student stu) { stu.Id = id; if (_repository.Update(stu) <= 0) { throw new HttpResponseException(HttpStatusCode.NotFound); } } //刪除操做(HttpDelete) public void DeleteStudent(int id) { Student stu = _repository.GetById(id); if (stu == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } _repository.Delete(stu); }
這節主要介紹了利用倉儲模式完整封裝EF來進行Web API基本操做,基本操做中關於返回狀態碼等信息,無非就是如下幾個對象spa
HttpResponseException 返回異常
HttpResponseMessage 返回信息(諸如狀態碼等)
HttpStatusCode 狀態碼枚舉(如頁面未找到等)