1

最初にEntityFrameworkコードを使用するMVC4プロジェクトで、より管理しやすいリポジトリパターンへの更新に取り組んでいます。基本的なCRUD操作を実行する汎用ベースリポジトリクラスを統合したので、作成する各リポジトリにこれらを実装する必要はありません。エンティティがTrackableEntityのタイプである場合、Allメソッドが削除されたフラグでクエリをフィルタリングする必要があるという問題が発生しました。エンティティはベースリポジトリでジェネリックであるため、キャストしようとしているのはTrackableEntityのタイプであり、次のエラーメッセージが表示されます。

タイプ'NameSpace.Models.ClientFormField'の入力とタイプ'NameSpace.Models.TrackableEntity'のチェックを持つ'TypeAs'式はサポートされていません。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);
}

これに関して私が抱えている問題は、コードを複製していることです。これは基本的にすべてのリポジトリにコピーアンドペーストするため、この新しいリポジトリパターンに変更する目的が無効になります。リポジトリ内の重複したコードを終了するように切り替えました。

これが私のエンティティの1つの例です。

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; }
}

これに関する助けをいただければ幸いです。

4

1 に答える 1

1

私はついに私が満足している解決策を手に入れました。最終的に2つの汎用リポジトリを作成しました。1つは、すべてのエンティティが継承するBaseEntityのデータベースへのすべての呼び出しを処理するベースリポジトリです。次に、BaesEntityを継承し、TrackableEntitiesのニーズを処理するためにいくつかのメソッドをオーバーライドする2番目の汎用リポジトリを作成しました。結局、これは、リポジトリ内からソフト削除されたアイテムのフィルタリングを処理することによって私が望むことを実行し、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;
    }
于 2012-12-10T01:09:16.297 に答える