在我的代码中的第(3)点,我定义了一个名为query1的查询,其中我定义了一个.Where lambda表达式.此查询在某种程度上是动态的,但仍包含静态元素,它始终引用Type Employee及其(int)属性ClientID.
现在我非常希望根据方法参数来引用类型及其属性动态,例如,如下面的点(1)所示.
到目前为止我尝试的是通过将(例如)(4),(5)和(6)中记载的更复杂的表达式树替换为使得在点(3)下定义的查询的静态部分完全动态化.但是,当我尝试将所有内容添加到一起时,它说我打电话.参数错误.我不知道如何调用.使用正确的参数来创建一个完全动态的选择.
有人知道解决这个问题吗?我花了一天时间搜索,到目前为止还没有找到解决方案.
dsMain domainService = new dsMain();
//(1)i want to rewrite the following four variables to method-parameters
Type entityType = typeof(Employee);
String targetProperty = "ClientID";
Type entityProperty = typeof(Employee).GetProperty(targetProperty).PropertyType;
int idToDelete = 5;
//(2)create expression-function: idToDelete == entityType.targetProperty (in this case: Employee.ClientID)
ParameterExpression numParam = Expression.Parameter(entityProperty, targetProperty.Substring(0, 3));
ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType());
BinaryExpression intEqualsID = Expression.Equal(numParam, equalTarget);
Expression<Func<int, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
intEqualsID,
new ParameterExpression[] { numParam });
//(3)I want to create query1 fully …Run Code Online (Sandbox Code Playgroud) 根据NHProf,不鼓励使用隐式交易:
http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions
但是,NHibernate LINQ IQueryable<>在从数据库中读取对象时返回一个,这是懒惰的评估.我在存储库中有这个方法:
public IQueryable<T> GetAll<T>()
{
using (var transaction = _session.BeginTransaction())
{
var data = _session.Linq<T>();
transaction.Commit();
return data;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是该方法将在data评估之前提交事务.有没有办法使用存储库模式并保持IQueryable<>显式事务?或者读取操作是否可以使用隐式事务?
在使用真实数据库之前构建一个应用程序,只是为了让事情有效我可以先使用硬编码列表作为虚假的内存存储库:
public class FakeProductsRepository
{
private static IQueryable<Product> fakeProducts = new List<Product> {
new Product{ ProductID = "xxx", Description = "xxx", Price = 1000},
new Product{ ProductID = "yyy", Description = "xxx", Price = 2000},
new Product{ ProductID = "zzz", Description = "xxx", Price = 3000}
}.AsQueryable();
public IQueryable<Product> Products
{
get { return fakeProducts; }
}
}
Run Code Online (Sandbox Code Playgroud)
如何向此类添加方法以动态地在此列表中添加新的,而不是硬编码的项目?
我有一个扩展方法,一个人真的很有帮助给我...它在IQueryable上做了一个命令...但我想要一个人做一个正常的IQueryable(非泛型)
这是代码,计数和跳过,我认为Take缺失.
public static IQueryable GetPage(this IQueryable query,
int page, int pageSize, out int count)
{
int skip = (int)((page - 1) * pageSize);
count = query.Count(); //COUNT DOESN'T EXIST
return query.Skip(skip).Take((int)pageSize); // NEITHER SKIP
}
Run Code Online (Sandbox Code Playgroud)
这是完美的,没有任何错误.
public static IQueryable<T> GetPage<T>(this IQueryable<T> query,
int page, int pageSize, out int count)
{
int skip = (int)((page - 1) * pageSize);
count = query.Count();
return query.Skip(skip).Take((int)pageSize);
}
Run Code Online (Sandbox Code Playgroud)
任何想法我怎么能解决这个问题?我不想改变我的返回类型,因为它完美地工作,我有另一个名为ToDataTable的扩展方法,它也可以在非泛型IQueryable上运行.
有工作吗?
提前致谢
编辑
我把它称为现有的IQueryable
IQueryable<Client> gen = null;
IQueryable nongen = null;
var test …Run Code Online (Sandbox Code Playgroud) 我正在尝试为我的EF存储库实现一个缓存方案,类似于此处的博客.正如作者和评论者所报告的那样,限制是密钥生成方法无法生成随给定查询的参数而变化的缓存键.这是缓存密钥生成方法:
private static string GetKey<T>(IQueryable<T> query)
{
string key = string.Concat(query.ToString(), "\n\r",
typeof(T).AssemblyQualifiedName);
return key;
}
Run Code Online (Sandbox Code Playgroud)
因此,以下查询将生成相同的缓存键:
var isActive = true;
var query = context.Products
.OrderBy(one => one.ProductNumber)
.Where(one => one.IsActive == isActive).AsCacheable();
Run Code Online (Sandbox Code Playgroud)
和
var isActive = false;
var query = context.Products
.OrderBy(one => one.ProductNumber)
.Where(one => one.IsActive == isActive).AsCacheable();
Run Code Online (Sandbox Code Playgroud)
请注意,唯一的区别在于isActive = true第一个查询和isActive = false第二个查询.
任何有效生成因IQueryable参数而异的缓存键的建议/见解都将得到真正的体会.
感谢Sergey Barskiy分享EF CodeFirst缓存方案.
我采用了遍历IQueryable表达式树的方法,目的是解析查询中使用的参数值.根据maxlego的建议,我扩展了System.Linq.Expressions.ExpressionVisitor类来访问我们感兴趣的表达式节点 - 在本例中是MemberExpression.更新的GetKey方法如下所示:
public …Run Code Online (Sandbox Code Playgroud) caching entity-framework iqueryable repository ef-code-first
有可能以Predicate<T> to Expression<Func<T, bool>>某种方式转换?
我想使用我的ICollectionView的过滤器使用下一个IQueryable函数:
public static System.Linq.IQueryable<TSource> Where<TSource>(this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<System.Func<TSource, bool>> predicate)
Run Code Online (Sandbox Code Playgroud)
谢谢
我遇到了类似的问题: LINQ to Entities无法识别方法'System.String ToString()'方法,并且此方法无法转换为存储表达式
我正在尝试对我的源进行分页,但在我的情况下,我不能将结果GetPropertyValue放在变量中,因为我需x要这样做:
public IEnumerable<TModel> Paginate(IQueryable<TModel> source, ref int totalPages, int pageIndex, int pageSize, string sortfield, SortDirection? sortdir)
{
totalPages = (int)Math.Ceiling(source.Count() / (double)pageSize);
if (sortdir == SortDirection.Descending)
{
return source.OrderByDescending(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
else
{
return source.OrderBy(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
}
private static object GetPropertyValue(object obj, string name)
{
return obj == null ? null : obj.GetType().GetProperty(name).GetValue(obj, null);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我该怎么办?
假设我有一个简单的存储库类,有一个GetByNames方法
public class MyRepo
{
private readonly MyDbContext _db;
public MyRepo(MyDbContext db)
{
_db = db;
}
public IQueryable<MyObject> GetByNames(IList<string> names)
{
if (names== null || !names.Any())
{
return Enumerable.Empty<MyObject>().AsQueryable();
}
return _db.MyObjects.Where(a => names.Contains(a.Name));
}
}
Run Code Online (Sandbox Code Playgroud)
现在当我使用异步EntityFramework ToListAsync()扩展时
var myObjects = awawit new MyRepo(_db).GetByNames(names).ToListAsync();
Run Code Online (Sandbox Code Playgroud)
如果我传入空列表或null,它会爆炸,因为Enumerable.Empty<MyObject>().AsQueryable()没有实现IDbAsyncEnumerable<MyObject>接口.
源IQueryable未实现IDbAsyncEnumerable.只有实现IDbAsyncEnumerable的源才能用于Entity Framework异步操作.有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=287068.
所以我的问题是,如何在没有访问数据库的情况下返回一个IQueryable<>实现的空IDbAsyncEnumerable?
在asp.net Web Api2中,当您为具有实体框架的模型创建异步Web api控制器时,默认情况下,新控制器中的第一个方法如下:
public IQueryable<MyModel> GetMyModel()
{
return db.MyModel;
}
Run Code Online (Sandbox Code Playgroud)
此方法的JSON输出只是所有MyModel条目的数组.同时,POST,PUT,GET(int id)和DELETE的所有其他方法都标记为async并返回Task<IHttpActionResult>.为什么不是同一风格的第一个GET方法,如下所示:
public async Task<IHttpActionResult> GetMyModel()
{
return Ok(await db.MyModel.ToArrayAsync());
}
Run Code Online (Sandbox Code Playgroud)
我试过这个,它产生相同的JSON输出.
我对这个问题有更好的标题的建议持开放态度.
对于使用Entity Framework足够长的人来说,您必然会遇到IQueryable<T>数据库无法执行生成的问题.这源于这样一个事实:IQueryable<T>除了内存实现(例如LINQ to objects)之外,不可能完全实现.诸如C#方法调用和使用Single/ SingleOrDefault作为非最终查询操作之类的事情在发送到真实IQueryProvider(例如MSSQL或Oralce)时会导致失败,但会传递单元测试.
我目前知道如何测试这些情况的唯一方法是实际运行该软件.虽然我同意该软件绝对应该作为编写新查询(或一般新代码)的一部分来完成,但如果使用单元测试可以找到这些类型的错误会很有帮助.导致我在这里的事件是发现了一个新的错误,我确信开发人员是一个无辜和安全的变化.更进一步,通过大量的单位测试给出了一种虚假的信心感.
是否有可能验证IQueryable<T>生产的产品实际上可以通过单元测试在特定的数据库技术(MSSQL,Oracle,等等)上运行?
var result = (
from a in session.Query<A>
where a.Field == SomeFunction(a)
select a
).ToList();
Run Code Online (Sandbox Code Playgroud)
由于数据库无法执行C#代码的明显原因,这将失败.
var result = (
from a in session.Query<A>
where a.Field == session.Query<B>().Single().Field
select a
).ToList();
Run Code Online (Sandbox Code Playgroud)
由于使用single作为非最终查询操作,这将失败.
还有其他情况,但我认为以上两个例子描述了我试图能够检测到的内容.
iqueryable ×10
c# ×7
linq ×4
asp.net ×1
async-await ×1
caching ×1
expression ×1
lambda ×1
linq-to-sql ×1
list ×1
nhibernate ×1
predicate ×1
repository ×1
transactions ×1
unit-testing ×1
where ×1