IEnumerable<dynamic> 与 linq
IEnumerable<dynamic> with linq
我正在尝试构建动态数据上下文,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语句
the problem with this solution is getting all data from database after that applying the where statement.
这里的问题不在于动态,而在于迭代源代码的方式。您正在使用 foreach
,并期望它被翻译成 SQL 或某种形式,但这是错误的假设。一旦通过 GetEnumerator()
方法调用创建迭代器,查询将是 "materialized",即使 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
参数的类型已更改为 Expression<Func<,>>
.
经过长时间的搜索,找到了适合我的解决方案
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();
我正在尝试构建动态数据上下文,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语句the problem with this solution is getting all data from database after that applying the where statement.
这里的问题不在于动态,而在于迭代源代码的方式。您正在使用 foreach
,并期望它被翻译成 SQL 或某种形式,但这是错误的假设。一旦通过 GetEnumerator()
方法调用创建迭代器,查询将是 "materialized",即使 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
参数的类型已更改为 Expression<Func<,>>
.
经过长时间的搜索,找到了适合我的解决方案
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();