5

いくつかの依存関係を逆転させるために、アプリケーションをリファクタリングしています。元のコードの一部は、DbContext.Set<MyEntityType>()クエリ対象のセットを取得するために使用します。

反転により、 MyEntityType はコードを使用して明示的に認識されなくなったDbContext.Set<MyEntityType>()ため、代わりに使用していDbContext.Set(TypeVariable)ます。

リファクタリングは、正しい DbSet が返される範囲で機能します。

ただし、タイプDbContext.Set(TypeVariable).LocalIList(含まれるタイプは不明) であるのに対し、 のタイプはDbContext.Set<MyEntityType>().LocalでしたObservableCollection<MyEntityType>。これは、DbSet に対して Linq を実行することが不可能になったことを意味します。

私が達成できた最善の回避策は、MyEntityType およびその他のエンティティ タイプが実装するインターフェイスにキャストすることです (明確にするために一部のコードは省略されています)。

var set = Context.Set(targetType);
var entity = set.Local.OfType<IActionTarget>()
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);
var querables = set as IQueryable<IActionTarget>;
entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);

だから、2つの質問:

DbContext.Set(TypeVariable)強く型付けされたセットを返さないのはなぜですか?

依存関係の逆転を行うより良い方法はありますか?

要求されたいくつかの詳細

依存関係がすべてです。Model には、通常の方法で EF Code First を介して (ただし、Repositoryを介して) 永続化される POCO クラスが含まれています。ActionEvaluatorは受信データを受け取り、Repository メソッドを介して、実行する必要があるアクションを決定します。つまり、DbSet に対するクエリです。

元のコードでは、1 種類の受信データ (特定の形式の CSV) しかなく、ActionEvaluator はこのデータに密接に依存しており、どの POCO クラスがどの CSV レコードに適用できるかを認識していました。

ここで、さまざまな CSV 形式と Web API メッセージを使用するように拡張したいと考えています。これを行うには、依存関係を反転して、DataSourceが ActionEvaluator にレコードが適用される POCO クラスを伝える必要があります。これは Type 変数によって行われます。

そのため、ActionEvaluator はジェネリック型パラメーターを使用できなくなりましたが、型変数をリポジトリに渡して、正しい DbSet を見つけることができます。

DbContext.Set<AnEntity>()問題は、DbSetを見つける 2 つの方法の違いDbContext.Set(TypeVariable)です。

これら2つの戻り値を機能的に同等にするためにEFの機能強化を求めていると思いますが、2番目のバージョンの型は実行時に決定されるため、それは不可能かもしれません。

要求された完全なメソッド コードは次のとおりです。

    private IActionTarget DbContextGetEntity(Type targetType, IActionTarget key)
    {
        var set = Context.Set(targetType);
        if (set == null)
        {
            throw new Exception("Unable to find DbSet for type '{0}'".F(targetType.Name));
        }

        // Look in the local cache first
        var entity = set.Local.OfType<IActionTarget>()
            .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

        if (entity == null)
        {
            // If not found locally, hit the database
            var querables = set as IQueryable<IActionTarget>;
            if (querables != null)
            {
                entity = querables.FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);
            }
        }
        return entity;
    }

理想的には交換したい

var entity = set.Local.OfType<IActionTarget>()
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

var entity = set.Local.OfType(targetType)
    .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);
4

1 に答える 1

3

私はそれをコンパイルしていませんので、フォーマットの問題を許してください-同じことを達成するために動的タイプを使用できますか?

private IActionTarget DbContextGetEntity(Type targetType, IActionTarget key)
{
    dynamic instance = Activator.CreateInstance(targetType);
    return DbContextGetEntity(instance, key);
}

private IActionTarget DbContextGetEntity<T>(T instance, IActionTarget key)
    where T : class, IActionTarget
{
    var set = Context.Set<T>(targetType);
    if (set == null)
    {
        throw new Exception();
    }

    // Look in the local cache first
    var entity = set.Local
        .FirstOrDefault(l => l.Id == key.Id && l.EffectiveDate == key.EffectiveDate);

    if (entity == null)
    {
        // If not found locally, hit the database
        entity = set
            .FirstOrDefault(e => e.Id == key.Id && e.EffectiveDate == key.EffectiveDate);
    }
    return entity;
}
于 2013-03-18T18:35:34.733 に答える