我正在使用 Dynamic Linq(源代码)。遗憾的是,关于如何使用它的文档很少 :-) 在一个有趣的回旋效应中,有一个“进化”的版本。这个回旋效应是因为生成动态类的代码是基于我的一个响应 :-) 剩下的代码似乎非常优美... 并且有一套完整的单元测试和代码样例!!!请注意,这个第二个库是第一个库的超集,所以你可能可以将许多示例应用于第一个库! :-)
我正在添加一些静态方法来将 Dynamic Linq 查询的结果转换为 IEnumerable<object[]>
.... 示例代码:
using (var ctx = new Model1())
{
var result = ctx.MyTable
.Take(100)
.SimpleSelect(new[] { "ID", "Col1", "Col2" })
.ToObjectArray();
foreach (var row in result)
{
Console.WriteLine(string.Join(", ", row));
}
}
更复杂的例子:
var columnsNames = new[] { "SomeNullableInt32", "SomeNonNullableDateTimeColumn" };
var formatters = new Func<object, string>[]
{
x => x != null ? x.ToString() : null,
x => ((DateTime)x).ToShortDateString()
};
var result = ctx.MyTable.Take(100).SimpleSelect(columnsNames).ToObjectArray();
foreach (var row in result)
{
var stringRow = new string[row.Length];
for (int i = 0; i < row.Length; i++)
{
stringRow[i] = formatters[i](row[i]);
}
Console.WriteLine(string.Join(", ", stringRow));
}
这些类... 其中一个 (SimpleSelect
) 生成动态SQL Select,并“匿名化”字段名称。我这样做是因为对于每种返回类型,动态Linq都会在运行时生成一个类。除非程序结束,否则该类不会被卸载。通过将列匿名化(我将它们重命名为 Item1
、Item2
、Item3
等),我增加了相同类被重用的可能性。请注意,不同类型的列将生成不同的类!(int Item1, string Item2
的类与 int Item1, DateTime Item2
的类不同),另一个类 (ToObjectArray
) 返回一个更容易解析的 IEnumerable<object[]>
。
public static class DynamicLinqTools
{
private static ConcurrentDictionary<Type, Func<object, object[]>> Converters = new ConcurrentDictionary<Type, Func<object, object[]>>();
public static IQueryable SimpleSelect(this IQueryable query, string[] fields)
{
return query.Select(string.Format("new ({0})", string.Join(", ", fields.Select((x, ix) => string.Format("{0} as Item{1}", x, ix + 1)))));
}
public static IEnumerable<object[]> ToObjectArray(this IQueryable query)
{
Func<object, object[]> converter;
Converters.TryGetValue(query.ElementType, out converter);
if (converter == null)
{
var row = Expression.Parameter(typeof(object), "row");
var row2 = Expression.Variable(query.ElementType, "row2");
var cast = Expression.Convert(row, query.ElementType);
var assign = Expression.Assign(row2, cast);
var properties = query.ElementType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.CanRead && x.GetIndexParameters().Length == 0)
.ToArray();
var properties2 = Array.ConvertAll(properties, x => Expression.Convert(Expression.Property(row2, x), typeof(object)));
var array = Expression.NewArrayInit(typeof(object), properties2);
var body = Expression.Block(typeof(object[]), new[] { row2 }, assign, array);
var exp = Expression.Lambda<Func<object, object[]>>(body, row);
converter = exp.Compile();
Converters.TryAdd(query.ElementType, converter);
}
foreach (var row in query)
{
yield return converter(row);
}
}
}
IEnumerable<object[]>
”的方法。那将是完美的解决方案。 - xanatosDbDataReader
完全可以胜任。EF不是为处理这些事情而构建的。使用NHibernate将会很容易(使用CriteriaAPI和投影到object[]
)。 - xanatos