我将从一段代码开始:
var objectType = typeof(Department); // Department is entity class from linqdatacontext
using (var dataContext = new DataModel.ModelDataContext())
{
var entity = Expression.Parameter(objectType, "model");
var keyValue = Expression.Property(entity, "Id");
var pkValue = Expression.Constant(reader.Value);
var cond = Expression.Equal(keyValue, pkValue);
var table = dataContext.GetTable(objectType);
... // and here i don't how to proceed
}
我甚至不确定我是否正确构建了该表达式。但是简单地说,我需要在该表上动态调用SingleOrDefault()
以按主键查找实体。我发现的每个例子都使用GetTable<>()
的泛型变体,但我显然无法使用它。我可能忽视了一些事情......
答案 0 :(得分:1)
如果您使用的是.NET 4,则可以尝试将返回的对象转换为dynamic
,这样您就可以这样查询。
using (var dataContext = new DataModel.ModelDataContext())
{
var entity = Expression.Parameter(objectType, "model");
var keyValue = Expression.Property(entity, "Id");
var pkValue = Expression.Constant(reader.Value);
var cond = Expression.Equal(keyValue, pkValue);
var table = dataContext.GetTable(objectType);
var result = table.Where(ent => ((dynamic)ent).SomeField == "SomeValue");
}
答案 1 :(得分:1)
每当我构建表达式树时,我都想从我正在构建的示例开始:
() => dataContext.GetTable<TEntity>().SingleOrDefault(entity => entity.Id == 1);
由此,我们可以轻松剖析目标表达。你在那里;你只需要在表达式树中包含对GetTable
方法的调用,然后构建一个外部lambda表达式来调用整个事物:
using(var dataContext = new DataModel.ModelDataContext())
{
var getTableCall = Expression.Call(
Expression.Constant(dataContext),
"GetTable",
new[] { entityType });
var entity = Expression.Parameter(entityType, "entity");
var idCheck = Expression.Equal(
Expression.Property(entity, "Id"),
Expression.Constant(reader.Value));
var idCheckLambda = Expression.Lambda(idCheck, entity);
var singleOrDefaultCall = Expression.Call(
typeof(Queryable),
"SingleOrDefault",
new[] { entityType },
getTableCall,
Expression.Quote(idCheckLambda));
var singleOrDefaultLambda = Expression.Lambda<Func<object>>(
Expression.Convert(singleOrDefaultCall, typeof(object)));
var singleOrDefaultFunction = singleOrDefaultLambda.Compile();
return singleOrDefaultFunction();
}
我们必须将SingleOrDefault
调用转换为具有返回类型的对象,以便它可以作为Func<object>
函数的主体。
(未测试的)
编辑:参数化数据上下文和值
现在我们正在建立这个功能:
(dataContext, value) => dataContext.GetTable<TEntity>().SingleOrDefault(entity => entity.Id == value);
您可以将常量更改为参数,并将这些参数添加到您编译的函数中:
var dataContextParameter = Expression.Parameter(typeof(ModelDataContext), "dataContext");
var valueParameter = Expression.Parameter(typeof(object), "value");
var getTableCall = Expression.Call(
dataContextParameter,
"GetTable",
new[] { entityType });
var entity = Expression.Parameter(entityType, "entity");
var idCheck = Expression.Equal(
Expression.Property(entity, "Id"),
valueParameter);
var idCheckLambda = Expression.Lambda(idCheck, entity);
var singleOrDefaultCall = Expression.Call(
typeof(Queryable),
"SingleOrDefault",
new[] { entityType },
getTableCall,
Expression.Quote(idCheckLambda));
var singleOrDefaultLambda =
Expression.Lambda<Func<ModelDataContext, object, object>>(
Expression.Convert(singleOrDefaultCall, typeof(object)),
dataContextParameter,
valueParameter);
var singleOrDefaultFunction = singleOrDefaultLambda.Compile();
// Usage
using(var dataContext = new DataModel.ModelDataContext())
{
return singleOrDefaultFunction(dataContext, reader.Value);
}
答案 2 :(得分:0)
答案 3 :(得分:0)
我会亲自使用Reflection和LINQ dynamic query library。
您可以获取包含dataContext.Mapping.GetMetaType(objectType).IdentityMembers
的表格的所有密钥列表,然后使用dataContext.GetTable(objectType).Where(key.Name + "==@0", id)
行的内容访问数据。
显然,我在那里省了几步 - 如果你有多个键,你需要建立一个更全面的谓词,循环超过.IdentityMembers
,如果你总是只有一个键,你可以使用.First()。我也没有测试过它,但它应该非常接近。它可能总共有6到7行代码 - 如果你需要,我可以把它编写(并测试)。
编辑:LINQ动态查询库可以从Microsoft http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx下载 - 只需在项目中包含DynamicLINQ.cs即可。