0

したがって、バケットからリポジトリのコレクションを取得し、それらのリポジトリをループして、期限切れにする必要があるリポジトリ内のすべてのレコードを見つけてから期限切れにする必要があるメソッドがあります。Func を使用して Invoke を実行する方法がわかりません。何かご意見は?私は間違った道を進んでいますか?

    public void DeactivateNonTransversableExpiredRecords()
    {
        databucket = new AdminBucket(PublishingFactory.AuthoringContext);

        IEnumerable<Tuple<dynamic, Type>> nonTransversableList = this.GetNonTransversableRepositories(databucket);

        foreach (Tuple<dynamic, Type> repository in nonTransversableList)
        {
            Type repoType = repository.Item1.GetType(); // RepositoryType
            var method = repoType.GetMethod("FindBy"); // Method
            var entityType = repository.Item2; // EntityType

            // Not working
            IQueryable recordsToExpire = method.Invoke(new Func<BaseEntity, bool>((x) => x.IsActive));

            foreach (var row in recordsToExpire)
            {
                ((BaseEntity) row).IsActive = false;
                repository.Item1.Edit((BaseEntity) row);
            }
        }
    }`

編集: 解決策... @Eduard からの貢献は、この課題を解決する上で非常に貴重でした。彼の貢献に賛成票を投じますが、実装されたのは実際のソリューションではありませんでした。

寄贈されたコードを通じて、私が行っていたように IQueryable を動的変数に返すと、レコードをデータベースに保存しようとしたときに問題が発生することがわかりました。読み取り専用セットを使用する場合は、@ Eduard のソリューションがエレガントに機能します。

モデルの BaseRepository.FindBy()に、同じリポジトリ内のメソッドを呼び出すパブリケーション固有のメソッドを作成することになりました。この出版物固有のメソッドはIList<T>、出版物アプリケーションに を返します。これにより、コレクションを列挙して実行するときに動的変数が適切に機能し、.Edit()どのタイプがどのリポジトリに移動するかを気にする必要がなくなります。デフォルトを使用すると、「セッションで他のスレッドが実行されているため、新しいトランザクションは許可されていません」という EF5 の吐き気の原因となっ.FindBy()た a が返されました。IQueryable<T>

ここに作業サンプルがあります

モデルの BaseRepository コード

public IList<T> GetItemsToExpire(DateTime date)
{
    return this.GetActive(x => x.ExpirationDate <= date).ToList<T>();
}

public virtual IQueryable<T> GetActive(Expression<Func<T, bool>> predicate)
{
    return this.GetActive().Where(predicate);
}

public virtual new IQueryable<T> GetActive()
{
    return this.FindBy(entity => entity.IsActive)
}

パブリケーション サービス コード

public void DeactivateNonTransversableExpiredRecords()
{
    databucket = new AdminBucket(PublishingFactory.AuthoringContext);

    IEnumerable<dynamic> nonTransversableRepositories = this.GetNonTransversableRepositories(databucket);

    foreach (dynamic repository in nonTransversableRepositories)
    {
        dynamic activeRecordsReadyToExpire = repository.GetItemsToExpire(DateTime.Now.AddDays(-1));  
        foreach (var record in activeRecordsReadyToExpire)
        {
            ((BaseEntity)record).IsActive = false;
            repository.Edit(record, true);
        }
    }
}
4

3 に答える 3

1

私の直感に基づいて推測し、コードに 2 つの問題があるとします。

まず、FindBy メソッドは、静的メソッドではなく、インスタンス メソッドであることが最も確実です。そのため、渡すパラメータ (Func) とは別に、「FindBy」メソッドを呼び出す必要があるインスタンスも渡す必要があります。プラス: Invoke メソッドの署名を完全に尊重する必要があります。インスタンス用に 1 つのオブジェクト、パラメーター用に 1 つのオブジェクトの配列です。

第 2 に、おそらく DLR を使用しても問題なく、必要なメソッドを構文的に呼び出すことができます。

私のマイナーな変更に注意してください:

        Type repoType = repository.Item1.GetType(); // RepositoryType
        var method = repoType.GetMethod("FindBy"); // Method
        var entityType = repository.Item2; // EntityType

        // Should work
        IQueryable recordsToExpire = method.Invoke(
             repository.Item1, 
             new object[] { (Expression<Func<BaseEntity, bool>>)((x) => x.IsActive) }
        ) as IQueryable;

MethodInfo クラスの Invoke メソッドを見ると、最初のパラメーターが「this」パラメーターであることがわかります。つまり、Func < T, ReturnType > デリゲート型 (「FindBy」というメソッドはありません) で「FindBy」を呼び出そうとしていました。

より美的なアプローチは、フローに沿って進み、DLR を使用し、「動的」タイプの機能を使用することです。たとえば、次のようになります。

        //Type repoType = repository.Item1.GetType(); // RepositoryType
        //var method = repoType.GetMethod("FindBy"); // Method
        var entityType = repository.Item2; // EntityType

        // Should work
        dynamic someDynamicResult = repository.Item1.FindBy ((Expression<Func<BaseEntity, bool>>)((x) => x.IsActive));
        IQueryable whichAtRuntimeShouldActuallyBeAnIQueryable = someDynamicResult;

大きな編集

明示的な「IsActive」ラムダを動的に作成する必要がある場合は、次のようにできます。

public class SomeClass
{
    private static MethodInfo methodOf_CreateLambdaGeneric = 
        typeof(SomeClass).GetMethod("CreateIsActiveLambdaGeneric");

    public static Expression<Func<T, bool>> CreateIsActiveLambdaGeneric<T>() where T : BaseEntity {
        return x => x.IsActive;
    }
    public static LambdaExpression CreateIsActiveLambda(Type type) {
        MethodInfo particularized = methodOf_CreateLambdaGeneric.MakeGenericMethod(type);
        object theLambda = particularized.Invoke(null, null);
        return theLambda as LambdaExpression;
    }
    }

次に、これらのヘルパー メソッドを次のように使用します。

        //Type repoType = repository.Item1.GetType(); // RepositoryType
        //var method = repoType.GetMethod("FindBy"); // Method
        var entityType = repository.Item2; // EntityType

        // Should work
        LambdaExpression compatibleIsActiveLambda = SomeClass.CreateIsActiveLambda(entityType);
        dynamic someDynamicResult = repository.Item1.FindBy (compatibleIsActiveLambda as dynamic);
        IQueryable whichAtRuntimeShouldActuallyBeAnIQueryable = someDynamicResult;
于 2013-04-04T20:49:27.573 に答える
0

私の状況で何がうまくいったかについては、質問の解決策を参照してください。また、データベースへの書き戻しを心配していない場合は、@EduardDumitru ソリューションがうまく機能します。

于 2013-04-06T05:13:44.450 に答える
0

FindBy期待しているExpression<Func<TEntity, bool>>あなたが与えているFunc<TEntity, bool>

Func<ピースを落として、ただやってみましたmethod.Invoke((x) => x.IsActive)か?

于 2013-04-04T20:48:49.463 に答える