使用的是EntityFramework, Version=6.0.0.0,項目原本直接將EntityFramework的Entity拿到UI使用,后面想使用dto對象將數據庫的Entity與前台分離開,中間使用AutoMapper類的工具進行轉換,而原本的一些EntityFramework泛型方法卻出現問題了,比如有個基類的方法是這樣的:
public abstract class ServiceBase<T> : IServiceBase<T> where T : BaseEntity, new() { protected DefaultDataContext NewDB() { return new DefaultDataContext(); } public void Add(T entity) { using (var db = this.NewDB()) { db.Entry<T>(entity).State = EntityState.Added; db.SaveChanges(); } } public void Modify(T entity) { entity.LastUpdatedTime = DateTime.Now; using (var db = this.NewDB()) { db.Entry<T>(entity).State = EntityState.Modified; db.SaveChanges(); } } public void Delete(string id) { using (var db = this.NewDB()) { var entity = new T() { Id = id }; db.Entry<T>(entity).State = EntityState.Deleted; db.SaveChanges(); } } public T GetByID(string id) { using (var db = this.NewDB()) { return db.Set<T>().AsNoTracking().Where(p => p.Id == id).FirstOrDefault(); } } public IList<T> GetByQuery(BaseQuery query) { using (var db = this.NewDB()) { var pageQuery = db.Set<T>().AsNoTracking().OrderBy(p => p.CreatedTime); query.TotalRecordCount = pageQuery.Count(); return pageQuery.Page(query.PageIndex, query.PageSize).ToList(); } } }
原本泛型T直接傳入的是EntityFramework的實體,使用起來是沒問題的,但是現在由於從接口方面進行的隔離,所以繼承的接口泛型就不能是數據庫的實體泛型T了,而變成dto的泛型TDto:
public abstract class ServiceBase<TDto> : IServiceBase<TDto> where TDto : BaseEntity, new() {}
而Entity與Dto的對應關系,已經用列表存儲起來,用來初始化AutoMapper映射工具:
class MapMember { public MapMember(Type from, Type to, bool isTwoWay = true) { From = from; To = to; IsTwoWay = isTwoWay; } public Type From { set; get; } public Type To { set; get; } public bool IsTwoWay { set; get; } }
按原本的設想,應該直接小改一下原來的代碼就可以的,因為EntityFramework的DbContext中,同時提供了DbSet<TEntity> Set<TEntity>() 以及 DbSet Set(Type entityType) ,正常看來,兩個方法應該能返回一樣的對象進行調用,但是實際使用的時候發現不同了,使用DbSet Set(Type entityType)返回的對象,無法正常調用上述的方法,經過一番搜索,發現兩個方法返回的對象存在差異,有看到類似使用.Cast解決方法,雖然編譯能過,但是運行的時候會報錯。
后面換了個思路,在已知Type的情況下,如何調用泛型<T>方法,暫時找到了一個解決方法:
public IList<TDto> GetByQuery(BaseQuery query) { Type l_entityType = DtoExtensions.GetMapType<TDto>(); dynamic l_entity = l_entityType.Assembly.CreateInstance(l_entityType.FullName); using (var db = NewDB()) { return DbBaseQueryToList(l_entity, db, query); } } private IList<TDto> DbBaseQueryToList<TEntity>(TEntity tEntity, DefaultDbContext db, BaseQuery query) where TEntity : BaseEntity { var l_pageQuery = new FromDbSet<TEntity>(tEntity, db).m_fromDbSet.AsNoTracking().OrderBy(p=>p.CreatedTime); return l_pageQuery.Page(query.PageIndex, query.PageSize).ToList().ToMapList<TDto>(); }
public class FromDbSet<T> where T : BaseEntity { public DbSet<T> m_fromDbSet; public FromDbSet(T o, DefaultDbContext db) { if (o.GetType() == typeof(BaseEntity)) throw new NotSupportedException("不支持基類"); m_fromDbSet = db.Set<T>(); } }
測試運行了一下,終於不會報錯了。不過中間多了這么些步驟估計是會影響效率的,目前來說影響不大,而且也可以通過重寫的方式覆蓋掉泛型方法,所以先就這樣了。如果您有更好的解決方式歡迎提出來共同探討!