我正在尝试构建动态数据上下文,linq不支持动态类型 我在
上找到了这个解决方案http://jrwren.wrenfam.com/blog/2010/03/04/linq-abuse-with-the-c-4-dynamic-type/
public static class ObjectExtensionMethod
{
public static IEnumerable<dynamic> Select(this object source, Func<dynamic, dynamic> map)
{
foreach (dynamic item in source as dynamic)
{
yield return map(item);
}
}
public static IEnumerable<dynamic> Where(this object source, Func<dynamic, dynamic> predicate)
{
foreach (dynamic item in source as dynamic)
{
if (predicate(item))
yield return item;
}
}
}
此解决方案的问题是在应用where语句之后从数据库获取所有数据。有没有办法在从动态类型
的数据库获取数据之前应用where语句答案 0 :(得分:2)
此解决方案的问题是在应用where语句之后从数据库获取所有数据。
这里的问题不是动态的,而是你在源上迭代的方式。您正在使用foreach
,并希望将其转换为SQL或类似,但这只是错误的假设。一旦迭代器由GetEnumerator()
方法调用创建,查询将“物化”,即使source
的实际类型正在实现IQueryable<T>
,结束其他所有内容都将在内存中执行。
如果您希望将条件转换为SQL,则需要to implement IQueryableProvider。
或者,至少你可以尝试调用底层IQueryableProvider
。但我不确定它是否有用。
public static class ObjectExtensionMethod
{
public static IQueryable Select<T>(this IQueryable source, Expression<Func<dynamic, dynamic>> map)
{
var method = new Func<IQueryable<dynamic>, Expression<Func<dynamic, dynamic>>, IQueryable<dynamic>>(Queryable.Select).Method;
var call = Expression.Call(null, method, source.Expression, Expression.Quote(map));
return source.Provider.CreateQuery(call);
}
public static IQueryable Where(this IQueryable source, Expression<Func<dynamic, bool>> predicate)
{
var method = new Func<IQueryable<dynamic>, Expression<Func<dynamic, bool>>, IQueryable<dynamic>>(Queryable.Where).Method;
var call = Expression.Call(null, method, source.Expression, Expression.Quote(predicate));
return source.Provider.CreateQuery(call);
}
}
请注意,source
参数的类型已从object
更改为IQueryable
,map
和predicate
参数的类型已更改为{{1} }。
答案 1 :(得分:0)
经过长时间搜索为我工作的解决方案
public static class ObjectExtensionMethod
{
public static IQueryable Select(this IQueryable source, Expression<Func<dynamic, dynamic>> map)
{
try
{
var method = new Func<IQueryable<dynamic>, Expression<Func<dynamic, dynamic>>, IQueryable<dynamic>>(Queryable.Select).Method;
Expression conversion = Expression.Convert(source.Expression, typeof(System.Linq.IQueryable<dynamic>));
var call = Expression.Call(null, method, conversion, Expression.Quote(map));
return source.Provider.CreateQuery(call);
}
catch (Exception ex)
{
return null;
}
}
public static IQueryable Where<T>(this IQueryable source, Expression<Func<T, bool>> predicate)
{
try
{
var method = new Func<IQueryable<T>, Expression<Func<T, bool>>, IQueryable<T>>(Queryable.Where).Method;
Expression conversion = Expression.Convert(source.Expression, typeof(System.Linq.IQueryable<T>));
var call = Expression.Call(null, method, conversion, predicate);
return source.Provider.CreateQuery(call);
}
catch (Exception ex)
{
return null;
}
}
public static IEnumerable<dynamic> ToList(this IQueryable source)
{
return source as dynamic;
}
}
问题是知道通过Expression<Func<dynamic, dynamic>>
解决这个问题
public Expression<Func<T, Boolean>> GetWhereFunc<T>(List<WhereCondition> searchFieldList,T item)
{
try
{
if (searchFieldList == null || searchFieldList.Count == 0)
{
return null;
}
ParameterExpression pe = Expression.Parameter(item.GetType(), "c");
//ParameterExpression pe = Expression.Parameter(typeof(object), "c");
Type itemType = item.GetType();
//combine them with and 1=1 Like no expression
Expression combined = null;
Type tempPropType;
if (searchFieldList != null)
{
foreach (WhereCondition fieldItem in searchFieldList)
{
if (string.IsNullOrEmpty(fieldItem.Value))
continue;
if (!string.IsNullOrEmpty(fieldItem.GridTblName))
continue;
//Expression for accessing Fields name property
Expression columnNameProperty = Expression.Property(pe, fieldItem.ColumName);
//the name constant to match
Expression columnValue = null;
tempPropType = itemType.GetProperty(fieldItem.ColumName).PropertyType;
if (tempPropType == typeof(DateTime) || tempPropType == typeof(DateTime?))
{
if (string.IsNullOrEmpty(fieldItem.Value))
{
}
else
{
DateTime tempdate = DateTime.Parse(fieldItem.Value);
TimeZone zoneclient = TimeZone.CurrentTimeZone;
TimeSpan spclient = zoneclient.GetUtcOffset(tempdate);
tempdate = tempdate.AddMinutes(-1 * spclient.TotalMinutes);
fieldItem.Value = tempdate.ToString();
}
}
if (tempPropType == typeof(Guid) || tempPropType == typeof(Guid?))
{
if (string.IsNullOrEmpty(fieldItem.Value))
{
columnValue = Expression.Constant(null);
}
else
{
if (tempPropType == typeof(Guid?))
{
columnValue = Expression.Constant((Guid?)Guid.Parse(fieldItem.Value), typeof(Guid?));
}
else
{
columnValue = Expression.Constant(Guid.Parse(fieldItem.Value));
}
}
}
else if (tempPropType.IsGenericType && tempPropType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (string.IsNullOrEmpty(fieldItem.Value))
{
columnValue = Expression.Constant(null);
}
else
{
columnValue = Expression.Constant(Convert.ChangeType(fieldItem.Value, tempPropType.GetGenericArguments()[0])
, tempPropType);
}
}
else
{
columnValue = Expression.Constant(Convert.ChangeType(fieldItem.Value, tempPropType));
}
Expression e1 = null;
MethodInfo method;
switch (fieldItem.Cond)
{
case Condetion.Equal:
e1 = Expression.Equal(columnNameProperty, columnValue);
break;
case Condetion.Greater:
e1 = Expression.GreaterThan(columnNameProperty, columnValue);
break;
case Condetion.GreaterOrEqual:
e1 = Expression.GreaterThanOrEqual(columnNameProperty, columnValue);
break;
case Condetion.Lower:
e1 = Expression.LessThan(columnNameProperty, columnValue);
break;
case Condetion.LowerOrEqual:
e1 = Expression.LessThanOrEqual(columnNameProperty, columnValue);
break;
case Condetion.NotEqual:
e1 = Expression.NotEqual(columnNameProperty, columnValue);
break;
case Condetion.Contaiens:
if (fieldItem.IsContaien)
{
Type tt = fieldItem.Values.GetType();
if (tt == typeof(List<dynamic>))
{
IEnumerable<dynamic> val = fieldItem.Values.Cast<dynamic>().ToList();
var someValueContain = Expression.Constant(val, val.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(object));
e1 = Expression.Call(someValueContain, "Contains", new Type[] { }, convertExpression);
}
else
{
var mval = fieldItem.Values.AsQueryable().Cast<dynamic>();
var someValueContain = Expression.Constant(mval, mval.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(object));
e1 = Expression.Call((
((Expression<Func<bool>>)
(() => Queryable.Contains(default(IQueryable<dynamic>), default(object))))
.Body as MethodCallExpression).Method,
someValueContain,
convertExpression);
}
}
else
{
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValueContain = Expression.Constant(fieldItem.Value, columnValue.Type);
e1 = Expression.Call(columnNameProperty, method, someValueContain);
}
break;
case Condetion.StartWith:
method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var someValueStartWith = Expression.Constant(fieldItem.Value, columnValue.Type);
e1 = Expression.Call(columnNameProperty, method, someValueStartWith);
break;
case Condetion.EndWith:
method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
var someValueEndWith = Expression.Constant(fieldItem.Value, columnValue.Type);
e1 = Expression.Call(columnNameProperty, method, someValueEndWith);
break;
case Condetion.NotContaiens:
if (fieldItem.IsContaien)
{
Type tt = fieldItem.Values.GetType();
if (tt == typeof(List<dynamic>))
{
IEnumerable<dynamic> val = fieldItem.Values.Cast<dynamic>().ToList();
var someValueContain = Expression.Constant(val, val.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(object));
e1 = Expression.Call(someValueContain, "Contains", new Type[] { }, convertExpression);
e1 = Expression.Not(e1);
}
else
{
var mval = fieldItem.Values.AsQueryable().Cast<dynamic>();
var someValueContain = Expression.Constant(mval, mval.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(object));
e1 = Expression.Call((
((Expression<Func<bool>>)
(() => Queryable.Contains(default(IQueryable<dynamic>), default(object))))
.Body as MethodCallExpression).Method,
someValueContain,
convertExpression);
e1 = Expression.Not(e1);
}
}
else
{
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValueContain = Expression.Constant(fieldItem.Value, columnValue.Type);
e1 = Expression.Call(columnNameProperty, method, someValueContain);
e1 = Expression.Not(e1);
}
break;
}
if (combined == null)
{
combined = e1;
}
else
{
combined = Expression.And(combined, e1);
}
}
}
if (combined == null)
{
return null;
}
var mm = Expression.Lambda<Func<T, bool>>(combined, pe);
return mm;//.Compile();
}
catch (Exception ex)
{
Logs.Log(ex);
return null;
}
}
public class WhereCondition
{
public string ColumName { set; get; }
public string Value { set; get; }
public Condetion Cond { set; get; }
public string GridTblName { set; get; }
public IEnumerable<dynamic> Values { set; get; }
public bool IsContaien { set; get; }
public WhereCondition(string columName, string value, Condetion cond)
{
ColumName = columName;
Value = value;
Cond = cond;
}
public WhereCondition()
{
ColumName = "";
Value = "";
Cond = Condetion.Equal;
}
}
public enum Condetion { Equal, Greater, GreaterOrEqual, Lower, LowerOrEqual, NotEqual, Contaiens, NotContaiens, StartWith,EndWith }
我们现在可以像这样调用查询。
WhereCondition whereCondition = new WhereCondition();
whereCondition.ColumName = "Id";
whereCondition.Cond = Condetion.Equal;
whereCondition.Value = id.ToString();
Expression<Func<T, bool>> whereEx = GetWhereFunc(new List<WhereCondition>(){whereCondition}, GetType());
return (from c in RDaynamicContext.GetTable(tbl)
select c).Where(whereEx).FirstOrDefault();