4

まず、少し背景。ASP.NET WebAPIとEntityFramework5を使用してRESTAPIを開発していますが、システムの要件は、ApiControllerとDbContextの間にロジックのいくつかのレイヤーが存在することです。これらのロジックのレイヤーには、エンティティをDbContextから切り離し、メモリ内のエンティティに仮想的な変更のセットを適用し(変更セットのマテリアライゼーションと呼んでいるプロセス、これらの変更が発生した場合にユーザーがシステムの新しい状態を検査できるようにすることが含まれます。適用。エンティティの新しい状態は、データベースにすぐには保存されません。代わりに、マテリアライゼーションはWebサーバーのメモリに保持され、ユーザーは現在のデータまたはさまざまな変更セットの多くのマテリアライゼーションの1つを検査できます。

今私の問題のために。

public interface IIdentifiable
{
    long Id { get; set; }
}

public class Foo : IIdentifiable
{
    public long Id { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; } // Navigation Property
}

public class Bar : IIdentifiable
{
    public long Id { get; set; }
    public string Name { get; set; }
    public long FooId { get; set; } // Foreign Key Property
    public Foo Foo { get; set; } // Navigation Property
}

public class Materialization
{
    IEnumerable<Foo> Foos { get; set; } 
    IEnumerable<Bar> Bars { get; set; } 
}

public interface IRepository<TItem> : IQueryable<TItem>, ICollection<TItem>, IDisposable
    where TItem : class, IIdentifiable
{
    IRepository<TItem> Include<TProperty>(Expression<Func<TItem, TProperty>> path);
    // Other methods
}

public class MateriailizationRepository<TItem> : IRepository<TItem>
    where TItem : class, IIdentifiable
{
    private Materialization _materialization;

    public MateriailizationRepository(Materialization materialization)
    {
        _materialization = materialization;
    }

    public IRepository<TItem> Include<TProperty>(Expression<Func<TItem, TProperty>> path)
    {
        // Populate navigation property indicated by "path"
    }

    // Other methods
}

Foo各バーには、それが属することを示す外部キープロパティがありますが、マテリアライゼーションプロセスが複雑になるためBar.FooFoo.Barsナビゲーションプロパティにはデータが入力されません。したがって、マテリアライズが完了した後、Materialization.Foos外部Materialization.Barsキープロパティによって相互に参照するが、ナビゲーションプロパティによっては参照しないオブジェクトのコレクションが含まれます(つまり、すべてのナビゲーションプロパティの値がnullまたは空になりますList<T>)。で次のようなことができるようになりたいですApiController

public IQueryable<Foo> Get (bool includeBars = false)
{
    Materialization materialization;

    // Materialize

    using (IRepository<Foo> repository = new MateriailizationRepository<Foo>(materialization))
    {
        IRepository<Foo> query = repository;

        if (includeBars)
            query = query.Include(f => f.Bars);

        return query;
    }
}

MateriailizationRepository<Foo>の主な責任はマテリアライズドオブジェクトをフェッチすることFooですが、それは全体への参照を持っているので、オンデマンドからマテリアライズドオブジェクトMaterializationを含めることができるようにしたいと思います。BarMateriailization.Bars

拡張メソッドMateriailizationRepository.Include()を模倣するためにどのように実装しますか?IQueryable.Include()

4

1 に答える 1

0

以下にいくつかのオプションを示します。

  1. 別のコンテキストを使用して MaterializationRepositories を実装し、それが現在でも機能している場合は、Effortなどのメモリ内データベースでサポートすることを検討してください。
  2. マテリアライゼーションで「インクルード」機能を自分で再実装します。Expression を分解して、ナビゲーション プロパティのタイプを見つけることができます。命名規則を使用すると、正しい識別子を取得するために照会する必要がある外部キー プロパティを特定できます。ターゲット リポジトリを見つけるには、マテリアライゼーションのリフレクションを使用して、ナビゲーション プロパティの型の IEnumerable 型のパブリック プロパティを探します。ターゲット エンティティの主キーの名前を知っている限り (たとえば慣例により)、外部キーの値を使用してそれを見つけることができます。

エンティティ タイプの数が少ない場合は、ある種の switch ステートメントを使用して、リフレクションではなく手動で実行する方がよいでしょう。

これが完全に実装されていないことをお詫びしますが、正しい方向に進むことを願っています.

于 2014-02-12T14:49:28.617 に答える