0

所以我有一个方法,我需要从我的 Bucket 中获取存储库的集合,遍历这些存储库并找到存储库中需要过期的所有记录,然后将它们过期。我在弄清楚如何使用 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()而不必担心什么类型进入什么存储库。使用默认.FindBy()返回的 aIQueryable<T>导致 EF5 吐出“不允许新事务,因为会话中正在运行其他线程”。

这是一个工作示例

模型的 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 方法的签名:一个对象用于实例,一个对象数组用于参数。

第二,您可能会很好地使用 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” lambda,您可以这样做:

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

FindBy期待Expression<Func<TEntity, bool>>你给它一个Func<TEntity, bool>

您是否尝试过放下这Func<件作品而只是做method.Invoke((x) => x.IsActive)

于 2013-04-04T20:48:49.463 回答
0

请参阅问题中的解决方案,了解我的情况。此外,如果您不担心写回数据库,那么@EduardDumitru 解决方案将非常有效。

于 2013-04-06T05:13:44.450 回答