我一直在网上和网上看过很多帖子,但似乎都没有帮助。
我有一张包含大约200万条记录的表格,它有超过200列。
一个简单的Web服务允许用户从表中提取特定数量的列,用户可以选择要提取的列。
结果需要是逗号分隔值的字符串,因此我的查询需要拉取请求的列并返回一个连接字符串。
我使用ADO.NET和纯SQL查询完成了这项工作,但是我被要求在实体框架中执行此操作。
这是我已经做过的事情。
我将请求的列列表作为字符串数组。
以下是我的询问,不确定这是否是最好的解决方案或想法,因此我在这里寻求帮助。
var valueList2 = ctx.mytable.Where(x => x.pcds == comValue).Select(x => new{temp = x.column1 +", "+ x.column2}).Select(x => x.temp).ToList();
上面给出了用逗号分隔的两列的字符串,我只需要以某种方式将我的列名列推送到它的lambda部分。
我做了以下但后来意识到它只适用于非匿名类的特定类型,我也无法弄清楚如何将它用于多列并且不会使它如此复杂。
var createdType = typeof(mytable);
var Param = Expression.Parameter(typeof(string), "pr");
var obj = Expression.New(createdType);
var ValueProperty = createdType.GetProperty("long");
var ValueAssignment = Expression.Bind(ValueProperty, Param);
var memberInit = Expression.MemberInit(obj, ValueAssignment);
var lm = Expression.Lambda<Func<string, mytable>>(memberInit, Param);
谢谢
答案 0 :(得分:1)
我正在使用Dynamic Linq(source code)。可悲的是,关于如何使用它的文档很少:-)在一个有趣的回旋镖效果中,there is an "evolved" version。回旋效应是因为用于生成动态类的代码基于我的一个响应:-)其余的代码似乎非常漂亮......并且有一个full suit of unit tests with code samples!!!请注意,这第二个库是一个超集第一个库,所以你可以在第一个库中应用很多例子! : - )
我正在添加一些静态方法来将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" };
// One for each column!
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选择,并“匿名”字段名称。我这样做是因为对于每种类型的返回,Dynamic 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)
{
// With a little luck, "anonymizing" the field names we should
// reduce the number of types created!
// new (field1 as Item1, field2 as Item2)
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");
// ElementType row2;
var row2 = Expression.Variable(query.ElementType, "row2");
// (ElementType)row;
var cast = Expression.Convert(row, query.ElementType);
// row2 = (ElementType)row;
var assign = Expression.Assign(row2, cast);
var properties = query.ElementType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.CanRead && x.GetIndexParameters().Length == 0)
.ToArray();
// (object)row2.Item1, (object)row2.Item2, ...
var properties2 = Array.ConvertAll(properties, x => Expression.Convert(Expression.Property(row2, x), typeof(object)));
// new object[] { row2.Item1, row2.Item2 }
var array = Expression.NewArrayInit(typeof(object), properties2);
// row2 = (ElementType)row; (return) new object[] { row2.Item1, row2.Item2 }
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);
}
}
}
答案 1 :(得分:0)
对于需要不同答案的人来说,这是一个简短而简单的答案,但根据我们与@xanatos的讨论,它不是最好的,因为它还会返回所有需要在删除之前切断的列。字符串列表。
List<string> valueList = new List<string>();
using (var ctx = new DataEntities1())
{
var query = ctx.myTable.Where(x => x.pcds == scode).SingleOrDefault();
foreach (var item in columnsArray)
{
valueList.Add(typeof(myTable).GetProperty(onsColumns[Convert.ToInt32(item)]).GetValue(query).ToString());
}
}