1

Castle Windsor IRepository パターンを使用して、LinqToSQL である DAL から抽象化するシステムを継承しました。

私が見ることができる主な問題は、IRepository が IEnumerable のみを実装していることです。そのため、最も単純なクエリでも、データテーブルからすべてのデータをロードして、単一のオブジェクトを返す必要があります。

現在の使用状況は以下の通り

using (IUnitOfWork context2 = IocServiceFactory.Resolve<IUnitOfWork>())
       {
           KpiFormDocumentEntry entry = context2.GetRepository<KpiFormDocumentEntry>().FindById(id, KpiFormDocumentEntry.LoadOptions.FormItem);

そして、これはラムダを使用してフィルタリングします。

public static KpiFormDocumentEntry FindById(this IRepository<KpiFormDocumentEntry> source, int id, KpiFormDocumentEntry.LoadOptions loadOptions)
    {
        return source.Where( qi => qi.Id == id ).LoadWith( loadOptions ).FirstOrDefault();
    }

したがって、それは素晴らしい拡張メソッドになります。

私の質問は、どうすればこの同じインターフェイス/パターンなどを使用できるだけでなく、IQueryable を実装して LinqToSQL を適切にサポートし、パフォーマンスを大幅に向上させることができますか?

IRepository の現在の実装/インターフェイスは次のとおりです。

public interface IRepository<T> : IEnumerable<T> where T : class
{

    void Add(T entity);

    void AddMany(IEnumerable<T> entities);

    void Delete(T entity);


    void DeleteMany(IEnumerable<T> entities);

    IEnumerable<T> All();

    IEnumerable<T> Find(Func<T, bool> predicate);

    T FindFirst(Func<T, bool> predicate);
}

そして、これは SqlClientRepository によって実装されます

public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
    private readonly Table<T> _source;

    internal SqlClientRepository(Table<T> source)
    {
        if( source == null ) throw new ArgumentNullException( "source", Gratte.Aurora.SHlib.labelText("All_TableIsNull",1) );
        _source = source;
    }

    //removed add delete etc 

    public IEnumerable<T> All()
    {
        return _source;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _source.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

現時点での問題は、上記の例では、.Where が 'GetEnumerator' を呼び出しており、すべての行をメモリにロードしてから、必要な行を探していることです。

IQueryable を実装するように IRepository を変更すると、必要な 3 つのメソッドを実装できなくなります。これらは Table クラスで公開されていないためです。

SQLClientRepository をそのように定義するように変更する必要があると思います

public sealed class SqlClientRepository<T> : IQueryable<T>, IRepository<T> where T : class

そして、必要なメソッドを実装しますが、表クラスのプライベートメンバーであるため、式を渡す方法などを理解できません。

public override Type ElementType
    {
        get { return _source.ElementType; } //Won't work as ElementType is private
    }

    public override Expression Expression
    {
        get { return _source.Expression; } //Won't work as Expression is private
    }

    public override IQueryProvider Provider
    {
        get { return _source.Provider; } //Won't work as Provider is private
    }

これを「ロード後にデータベース内のすべての行を反復処理する」から「select x where id=1」に移動することを本当に感謝しています!

4

2 に答える 2

0

したがって、もはや真の抽象化ではないかもしれませんが、要点は、すでに記述されているすべてのクエリを更新せずに、linqtosqlの利点を活用することでした。

そこで、IRepositoryにIEnumerableではなくIQueryableを実装させました。

次に、SqlClientRepository実装で、AsQueryable()を呼び出してテーブルをIQueryableにキャストできます。そうすれば、すべてがうまくいきます。

誰かがIRepository()。Where(qi => qi.id = id)などを書いたところはどこでも、実際にはIDをSQLサーバーに渡し、すべてではなく1つのレコードのみをプルバックし、ループして正しいもの。

/// <summary>Provides the ability to query and access entities within a SQL Server data store.</summary>
/// <typeparam name="T">The type of entity in the repository.</typeparam>
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
    private readonly Table<T> _source;
    private readonly IQueryable<T> _sourceQuery;

    IQueryable<T> Query()
    {
        return (IQueryable<T>)_source;
    }

    public Type ElementType
    {
        get { return _sourceQuery.GetType(); }
    }

    public Expression Expression
    {
        get { return _sourceQuery.Expression; }
    }

    public IQueryProvider Provider
    {
        get { return _sourceQuery.Provider; }
    }



    /// <summary>Initializes a new instance of the <see cref="SqlClientRepository{T}"/> class.</summary>
    /// <param name="source">A <see cref="Table{T}"/> to a collection representing the entities from a SQL Server data store.</param>
    /// <exception cref="ArgumentNullException"><paramref name="source"/> is a <c>null</c> reference (<c>Nothing</c> in Visual Basic).</exception>
    internal SqlClientRepository(Table<T> source)
    {
        if( source == null ) throw new ArgumentNullException( "source", "All_TableIsNull" ) );
        _source = source;
        _sourceQuery = _source.AsQueryable();
    }
于 2013-02-07T09:23:19.213 に答える
0

linq を公開したい場合は、リポジトリ パターンの使用をやめて、Linq2Sql を直接使用できます。これは、すべての Linq To Sql プロバイダーが独自のカスタム ソリューションを持っているためです。したがって、LINQ を公開すると、漏れのある抽象化が発生します。その場合、抽象化レイヤーを使用しても意味がありません。

LINQ を公開する代わりに、次の 2 つのオプションがあります。

  1. 仕様パターンの実装
  2. ここで説明するリポジトリ パターンを使用します: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
于 2013-02-06T11:02:54.590 に答える