使用反射调用FindBy方法,该方法接受存储库上的表达式
本文关键字:方法 存储 表达式 反射 调用 FindBy | 更新日期: 2023-09-27 18:07:23
所以我有一个方法,我需要从我的Bucket中获取存储库的集合,循环遍历这些存储库并找到存储库中需要过期的所有记录,然后使它们过期。我有一个问题,弄清楚如何执行调用使用一个函数。任何想法吗?我走错路了吗?
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返回给动态变量会在尝试将记录保存回数据库时引起问题。如果你想要一个只读集,那么@ edward的解决方案将会很好地工作。
我最终在模型的BaseRepository中创建了一个特定于发布的方法,该方法调用同一个Repository中的.FindBy()
方法。这个特定于发布的方法向发布应用程序返回一个IList<T>
。这允许动态变量在枚举集合和执行.Edit()
时正常工作,而不必担心什么类型到什么存储库。使用默认的.FindBy()
返回IQueryable<T>
,导致EF5呕吐说'不允许新的事务,因为有其他线程在会话中运行'。
这是一个工作示例
Model的BaseRepository Code
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);
}
}
}
我要根据我的直觉做一个假设,说我在你的代码中看到了两个问题。
首先,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,>委托类型(它没有名为"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" lambdas,你可以这样做:
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;
FindBy
期待一个Expression<Func<TEntity, bool>>
你给它一个Func<TEntity, bool>
你有没有试过放下Func<
块,只做method.Invoke((x) => x.IsActive)
?
请参阅问题中的解决方案,了解在我的情况下起作用的方法。此外,如果你不担心写回数据库,那么@EduardDumitru解决方案将工作得很好。