0

私は一連の Entity Framework (EF) ベースのリポジトリを持っています。そのうちのいくつかは、論理的に削除できるエンティティを処理します (すべてが削除できるわけではありません)。エンティティは EF によって自動生成されます。これまでのところ、私は持っています:

  • 論理的に削除できるエンティティは、ICanBeSoftDeleted インターフェイスを実装します。

    public interface ICanBeSoftDeleted
    {
        bool IsDeleted { get; set; }
    }
    
  • これらのエンティティには、ISoftDeleteRepository を実装するリポジトリを使用します。

    public interface ISoftDeleteRepository<T> : IRepository<T> where T : class, ICanBeSoftDeleted    
    {
        void SoftDelete(T entity);   
        void SoftDelete(Expression<Func<T, bool>> where);
    }
    
  • また、RepositoryBase を拡張してソフト削除メソッドを追加する SoftDeleteRepositoryBase という基本クラスもあります。

    public abstract class SoftDeleteRepositoryBase<T> : RepositoryBase<T> where T : class, ICanBeSoftDeleted
    {
        public virtual void SoftDelete(T entity)
        {
            entity.IsDeleted = true;
            Update(entity);
        }
    
        public virtual void SoftDelete(Expression<Func<T, bool>> where)
        {
            var entitiesToDelete = GetMany(where).AsEnumerable();
            foreach (T entity in entitiesToDelete)
            {
                this.Delete(entity);
            }
        }
    }
    

これはすべてうまくいきます。ただし、このコードは、リポジトリを直接呼び出すユーザーに配布される内部ライブラリの一部であり、「IsDeleted」プロパティを変更したり、メソッドを呼び出すエンティティのみを読み取ったり削除したりしたくありません。セッターが公開されているため、現在、彼らはそれを行うことができます。

これを行うためにコード設計を変更するにはどうすればよいですか? ICanBeSoftDeleted を変更してセッターを削除することはできません。これは、SoftDeleteRepositories から変更することができないためです。

ありがとう

更新:今のところ、インターフェイスから「セット」を削除し、リフレクションを使用してリポジトリに値を設定することで問題を解決しました:

public virtual void Delete(T entity)
{
    PropertyInfo propertyInfo = entity.GetType().GetProperty("IsDeleted");
    propertyInfo.SetValue(entity, true);

    Update(entity);
}

ただし、これはパッチのように感じます。より大きな設計上の問題を解決しているとは思いません...

4

4 に答える 4

1

EF クラスを壁の後ろに保持し、POCO にマップする必要があります。または、それらをコンシューマに渡すときに (setter を宣言しない) インターフェイスとしてそれらを入力します。

2 番目のオプションでは、オブジェクトを開いたままにして、リフレクションによって削除済みフラグを設定します。

編集:投稿したコードをさらに分析すると、次の質問につながります。

API のコンシューマーがリポジトリを宣言できるようにするつもりですか?

API で CustomerRepository、UserRepository、PurchaseRepository など、一般的でないリポジトリのみを公開する方が賢明と思われます。

非ジェネリック API は、API コンシューマーの POCO から EF クラスを分離できる明確な境界を形成します。

于 2013-07-10T16:41:32.863 に答える
1

代わりに、エンティティが RepositoryBase 内の ICanBeSoftDeleted の実装であるかどうかを確認してください。

ここから拡張機能を使用: http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/

public static class TypeExtensions
{
    //http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/
    public static bool IsImplementationOf(this Type baseType, Type interfaceType)
    {
        return baseType.GetInterfaces().Any(interfaceType.Equals);
    }
}

public interface IRepository<T> 
{
    void Delete(T entity);
}

public class RepositoryBase<T> : IRepository<T> where T : class
{
    public void Delete(T entity)
    {
        if (typeof(T).IsImplementationOf(typeof(ICanBeSoftDeleted)))
        {
            ((ICanBeSoftDeleted)entity).IsDeleted = true;
            //etc
        }
        else
        {
            //hard delete
        }
    }
}

public class Customer : ICanBeSoftDeleted
{
    public bool IsDeleted { get; set; }
}

public class UOW
{

    private IRepository<T> GetRepository<T>()
    {
        return (IRepository<T>)new RepositoryBase<T>();
    }

    public IRepository<Customer> CustomerRepository
    {
        get
        {
            return GetRepository<Customer>();
        }
    }
}

public interface ICanBeSoftDeleted
{
    bool IsDeleted { get; set; }
}
于 2013-07-11T10:10:17.693 に答える
0

これはどう:

public interface ICanBeSoftDeleted
{
    bool IsDeleted { get; }
}

public abstract class CanBeSoftDeleted : ICanBeSoftDeleted
{
    private bool _IsDeleted;
    public bool IsDeleted
    {
        get { return _IsDeleted; }
    }

    internal void SetIsDeleted(bool value) { _IsDeleted = value; }
}

次に、モデルは代わりに抽象クラスから継承できます

于 2013-07-12T13:34:25.093 に答える