1

IRepository<T>インターフェイス、NewsRepositoryクラス、Newsエンティティを用意することで、リポジトリパターンの実装をほぼ完了しました。私が遭遇した問題は、一般的なメソッドを基本リポジトリクラスに抽象化しようとしたことでした。

NewsRepositoryGetメソッドには特定のLinq式が含まれているため、Getメソッドを抽象化する方法が見つかりませんでした。

私の質問は

1)public T Get(int id)メソッドを基本クラスに抽象化するにはどうすればよいですか?これまで私が行った唯一の方法Expression<Func<T,bool>>は、intの代わりに渡すことですが、各サブクラスはそれぞれの場合でほぼ同じ式を渡す必要があるため、一般的な動作を実際に抽象化することはできません。n => n.id == id

2) Updateメソッドの基本クラスにサブクラスのGetViolationsとmapメソッドを渡すにはどうすればよいですか?解決策はおそらくデリゲートを使用することだと思いますが、コンパイルする構文を取得できませんでした

これはコードの簡略化されたセットです。実際には、ここに示されている更新だけでなく、更新と挿入を行うSaveメソッドがあります。

public interface IRepository<T>
{
    T Get(int id);
    void Update(T item);
}

public class NewsRepository : IRepository<News>
{
    private Table<News> _newsTable;
    public NewsRepository(string connectionString)
    {
        _newsTable = new DataContext(connectionString).GetTable<News>();
    }

    public News Get(int id)
    {
        return _newsTable.SingleOrDefault(n => n.NewsId == id);
    }

    public void Update(News item)
    {
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        News dbNews = _newsTable.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _newsTable.Context.SubmitChanges();
    }

    private void map(News dbNews, News news)
    {
        dbNews.Title = news.Title;
        dbNews.Article = news.Article;
    }
}

public class Repository<T> where T : class
{
    protected Table<T> _table;

    public Repository(Table<T> t)
    {
        _table = t;
    }

    //How do i do this??! - This doesn't compile due to T no having a NewsId
    public T Get(int id)
    {
    return _table.SingleOrDefault(n => n.NewsId == id);
    }

    //This seems to be a solution, but it's not really abstracting common behaviour as each
    //sub-class will still need to pass in the same linq expression...
    public T Get(Expression<Func<T,bool>> ex)
    {
        return _table.SingleOrDefault(ex);
    }

    public void Update(T item)
    {
        //How is it possible to pass in the GetRuleViolations and map functions to this method?
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        T dbNews = _table.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _table.Context.SubmitChanges();
    }
}
4

2 に答える 2

2
  1. L2Sは、レイヤースーパータイプもクエリでのインターフェイスメンバーの使用もサポートしていないため、再利用は非常に困難です。1つのオプションは、式ツリーを動的に構築することです。少し面倒ですが、基本クラスのリポジトリに分離すればそれほど悪くはありません。

次に例を示します。

public interface IEntity
{
    int Id { get; }
}

public partial class News : IEntity
{
}

public class Repository<T> where T : class, IEntity
{

    private readonly DataContext _db;

    public Repository(DataContext db)
    {
        _db = db;
    }

    public T Get(int id)
    {
        Expression<Func<T, bool>> hasId = HasId(id);
        return _db.GetTable<T>().Single(hasId);
    }

    // entity => entity.Id == id;   
    private Expression<Func<T, bool>> HasId(int id)
    {
        ParameterExpression entityParameter = Expression.Parameter(typeof (T), "entity");
        return Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(entityParameter, "Id"),
                Expression.Constant(id)
                ),
            new[] {entityParameter}
            );
    }
}

http://msdn.microsoft.com/en-us/library/bb397951.aspxも参照してください。

于 2009-05-25T20:57:23.043 に答える
1
  1. エンティティのレイヤースーパータイプがあると本当に役立ちます。それらはIdプロパティを共有します。idプロパティを表す式を処理する必要はなく、それが何であるかがわかります。

  2. テンプレートメソッドパターン。このパターンでは、ベースUpdateがヘルパーメソッドを呼び出すすべての作業を順番に実行し、派生クラスがそれらの保護された抽象ヘルパーメソッドを実装します。

于 2009-05-22T11:58:34.110 に答える