实体框架类型在谓词中使用泛型

时间:2012-11-06 06:07:03

标签: sql-server-2008 asp.net-mvc-4 entity-framework-5

我正在努力更新到我的MVC 4项目中更易于管理的存储库模式,该模式首先使用Entity Framework代码。我已经集成了一个通用的基础存储库类,它将执行基本的CRUD操作,因此我不必在我创建的每个存储库中实现这些。我遇到了一个问题,如果实体是一种TrackableEntity,我的All方法需要通过删除标志来过滤查询。由于实体在基本存储库中是通用的,我试图将其转换为一种TrackableEntity,其中只会导致以下错误消息。

  

不支持带有“NameSpace.Models.ClientFormField”类型输入的“TypeAs”表达式和“NameSpace.Models.TrackableEntity”类型的检查。 LINQ to Entities查询中仅支持实体类型和复杂类型。

此错误使得完成,因为我理解为什么我的代码不起作用,但我试图找到一种方法来过滤掉已删除的项目,而不必在我的所有存储库中覆盖此方法。我对All方法的代码如下。

public virtual IEnumerable<T> All()
{
    if (typeof(T).IsSubclassOf(typeof(TrackableEntity)))
        return dbSet.Where(e => !(e as TrackableEntity).IsDeleted).ToList();

    return dbSet.ToList();
}

我知道我可以做以下事情

public virtual IEnumerable<T> All(Expression<Func<T, bool>> predicate = null)
{
    if (predicate != null)
        return dbSet.Where(predicate).IsDeleted).ToList();

    return dbSet.ToList();
}

然后将其添加到我的所有存储库

public override IEnumerable<CaseType> All(Expression<Func<CaseType,bool>> predicate = null)
{
    if (predicate == null)
        predicate = e => !e.IsDeleted;
    return base.All(predicate);
}

我遇到的问题是我正在复制代码,这基本上是复制并粘贴到我的所有存储库中,这使得更改为新的存储库模式的目的失败了。我切换到了我的存储库中的重复代码。

以下是我的某个实体的示例。

public class CaseType : TrackableEntity, IValidatableObject
{
    public int Id { get; set; }
    public string Name { get; set; }

    public bool InUse { get; set; }

    public bool IsValid { get { return !this.Validate(null).Any(); } }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (String.IsNullOrEmpty(Name))
            yield return new ValidationResult("Case Type name cannot be blank", new[] { "Name" });

        //Finish Validation Rules
    }
}

TrackableEntity

public abstract class TrackableEntity
{
    public bool Active { get; set; }
    public bool IsDeleted { get; set; }
    public virtual User CreatedBy { get; set; }
    public virtual User ModifiedBy { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
}

对此的任何帮助都将非常感激。

1 个答案:

答案 0 :(得分:1)

我终于找到了一个我很满意的解决方案。我最终制作了2个通用存储库。一个是基本存储库,它处理所有实体继承的BaseEntity对数据库的所有调用。然后我制作了我的第二个通用仓库,它继承了BaesEntity并覆盖了一些方法来处理我的TrackableEntities的需求。最后,通过处理repo中软删除项目的过滤,我可以满足我的需求,同时也为TrackableEntity提供了更大的灵活性。

BaseRepository -

public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
{
    private readonly IAppDb _db;
    private readonly IDbSet<T> _dbSet;

    public BaseRepository(IAppDb db)
    {
        _db = db;
        _dbSet = Lwdb.Set<T>();
    }

    protected IAppDb Lwdb
    {
        get { return _db; }
    }

    #region IBaseRepository<T> Members

    public virtual T GetById(int id)
    {
        return _dbSet.Find(id);
    }

    public virtual T Add(T entity)
    {
        _dbSet.Add(entity);
        _db.Commit();
        return entity;
    }

    public virtual bool Any(Expression<Func<T, bool>> expression)
    {
        return _dbSet.Any(expression);
    }

    public virtual void Delete(T entity)
    {
        _dbSet.Remove(entity);
        _db.Commit();
    }

    public virtual IEnumerable<T> All()
    {
        return _dbSet.ToList();
    }

    public virtual T Update(T entity, bool attachOnly = false)
    {
        _dbSet.Attach(entity);
        _db.SetModified(entity);
        if (!attachOnly) _db.Commit();
        return entity;
    }

    #endregion

    protected User GetCurrentUser()
    {
        return
            _db.Set<User>().Find(HttpContext.Current != null ? ((User) HttpContext.Current.Session["User"]).Id : 1);
    }

BaseTrackableEntityRepository -

public class BaseTrackableEntityRepository<T> : BaseRepository<T>, IBaseTrackableEntityRepository<T>
    where T : TrackableEntity
{
    private readonly IAppDb _db;
    private readonly IDbSet<T> _teDB;

    public BaseTrackableEntityRepository(IAppDb db)
        : base(db)
    {
        _db = db;
        _teDB = _db.Set<T>();
    }

    #region IBaseTrackableEntityRepository<T> Members

    public virtual T SetDeleteFlag(int id)
    {
        var entity = _teDB.Find(id);
        if (entity == null) return null; //throw exception
        entity.IsDeleted = true;
        entity.DateModified = DateTime.Now;
        entity.ModifiedBy = GetCurrentUser();
        return Update(entity);
    }

    public override IEnumerable<T> All()
    {
        return _teDB.Where(e => !e.IsDeleted).ToList();
    }

    public override T Add(T entity)
    {
        var curUser = GetCurrentUser();
        entity.CreatedBy = curUser;
        entity.ModifiedBy = curUser;
        entity.DateCreated = DateTime.Now;
        entity.DateModified = DateTime.Now;
        entity.Active = true;
        entity.IsDeleted = false;
        _teDB.Add(entity);
        _db.Commit();
        return entity;
    }

    public override T Update(T entity, bool attachOnly = false)
    {
        InsertTeData(ref entity);
        entity.ModifiedBy = GetCurrentUser();
        entity.DateModified = DateTime.Now;
        _teDB.Attach(entity);
        _db.SetModified(entity);
        if (!attachOnly) _db.Commit();
        return entity;
    }

    public virtual T SetStatus(int id, bool status)
    {
        var entity = _teDB.Find(id);
        if (entity == null) return null;
        entity.Active = status;
        return Update(entity);
    }

    #endregion

    private void InsertTeData(ref T entity)
    {
        if (entity == null || entity == null) return;
        var dbEntity = GetById(entity.Id);
        if (dbEntity == null) return;
        _db.Detach(dbEntity);
        entity.CreatedBy = dbEntity.CreatedBy;
        entity.DateCreated = dbEntity.DateCreated;
        entity.ModifiedBy = dbEntity.ModifiedBy;
        entity.DateModified = dbEntity.DateModified;
    }