我的问题是,如果我可以预测或选择通过ToTraceString()
生成sql的列的确切顺序。
我使用ToTraceString()
获取IQueryable以获取生成的SQL命令,然后将结果直接插入数据库表中。
所以,我需要生成的SQL与我的表结构一致......
string insertQuery = string.Format("INSERT INTO {0} {1}", sqlTableName ((System.Data.Objects.ObjectQuery<TRow>)results).ToTraceString());
Context.ExecuteStoreCommand(string.Format("TRUNCATE TABLE {0}", sqlTableName));
Context.ExecuteStoreCommand(insertQuery);
results = IQueryable<Row>
其中Row是一个与表列具有相同属性的类型
我选择直接插入表中,因为我认为在Web服务器上获取ToList()是没有意义的,只是通过某种批量插入将其发送回SQL(EF不支持;当下......)我的查询返回了大量的行,我不想使用存储过程。
希望我有意义......谢谢
答案 0 :(得分:0)
this question的已接受答案包含两个链接,这两个链接描述了如何确定实体类型的各种属性在ToTraceString()生成的SQL中出现的顺序。有了这些信息,您可以对原始SQL进行一些简单的解析/重构,以替换EF使用的奇怪列名(例如C1,C2等)和属性列名。然后,您可以将生成的SQL包装在子查询中,该子查询按您想要的顺序选择相关列:
SELECT prop1, prop2
FROM
(
// the result of ToTraceString(), with EF's generated column names replaced by the property names of the query type
) x
答案 1 :(得分:0)
我有这个问题,但这里的答案仍需要相当多的工作才能开始。我使用How does Entity Framework manage mapping query result to anonymous type?的部分来获取顺序并返回名称,然后使用简单的解析来提取字段名称。
我制作了一个将所有内容集合在一起的扩展方法:
public static string ToWrappedString(this ObjectQuery query, out ObjectParameterCollection parameters)
{
var trace = query.ToTraceString();
parameters = query.Parameters;
var positions = query.GetPropertyPositions();
// the query should be SELECT\n
// Column AS NNN
// FROM
// so we regex this out
var regex = new Regex("^SELECT(?<columns>.*?)FROM", RegexOptions.Multiline);
var result = regex.Match(trace.Replace(Environment.NewLine, ""));
var cols = result.Groups["columns"];
// then we have the columns so split to get each
const string As = " AS ";
var colNames = cols.Value.Split(',').Select(a => a.Substring(a.IndexOf(As, StringComparison.InvariantCulture) + As.Length)).ToArray();
var wrapped = "SELECT " + String.Join(Environment.NewLine + ", ", colNames.Select((a, i) => string.Format("{0}{1} [{2}]", a, As, positions[i]))) + " FROM (" + trace
+ ") WrappedQuery ";
return wrapped;
}
这是来自其他链接的代码,更新为EF6内部并按列顺序而不是索引返回名称。
public static string[] GetPropertyPositions(this ObjectQuery query)
{
// get private ObjectQueryState ObjectQuery._state;
// of actual type internal class
// System.Data.Objects.ELinq.ELinqQueryState
object queryState = GetProperty(query, "QueryState");
AssertNonNullAndOfType(queryState, "System.Data.Entity.Core.Objects.ELinq.ELinqQueryState");
// get protected ObjectQueryExecutionPlan ObjectQueryState._cachedPlan;
// of actual type internal sealed class
// System.Data.Objects.Internal.ObjectQueryExecutionPlan
object plan = GetField(queryState, "_cachedPlan");
AssertNonNullAndOfType(plan, "System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan");
// get internal readonly DbCommandDefinition ObjectQueryExecutionPlan.CommandDefinition;
// of actual type internal sealed class
// System.Data.EntityClient.EntityCommandDefinition
object commandDefinition = GetField(plan, "CommandDefinition");
AssertNonNullAndOfType(commandDefinition, "System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition");
// get private readonly IColumnMapGenerator EntityCommandDefinition._columnMapGenerator;
// of actual type private sealed class
// System.Data.EntityClient.EntityCommandDefinition.ConstantColumnMapGenerator
var columnMapGeneratorArray = GetField(commandDefinition, "_columnMapGenerators") as object[];
AssertNonNullAndOfType(columnMapGeneratorArray, "System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition+IColumnMapGenerator[]");
var columnMapGenerator = columnMapGeneratorArray[0];
// get private readonly ColumnMap ConstantColumnMapGenerator._columnMap;
// of actual type internal class
// System.Data.Query.InternalTrees.SimpleCollectionColumnMap
object columnMap = GetField(columnMapGenerator, "_columnMap");
AssertNonNullAndOfType(columnMap, "System.Data.Entity.Core.Query.InternalTrees.SimpleCollectionColumnMap");
// get internal ColumnMap CollectionColumnMap.Element;
// of actual type internal class
// System.Data.Query.InternalTrees.RecordColumnMap
object columnMapElement = GetProperty(columnMap, "Element");
AssertNonNullAndOfType(columnMapElement, "System.Data.Entity.Core.Query.InternalTrees.RecordColumnMap");
// get internal ColumnMap[] StructuredColumnMap.Properties;
// array of internal abstract class
// System.Data.Query.InternalTrees.ColumnMap
Array columnMapProperties = GetProperty(columnMapElement, "Properties") as Array;
AssertNonNullAndOfType(columnMapProperties, "System.Data.Entity.Core.Query.InternalTrees.ColumnMap[]");
int n = columnMapProperties.Length;
string[] propertyPositions = new string[n];
for (int i = 0; i < n; ++i)
{
// get value at index i in array
// of actual type internal class
// System.Data.Query.InternalTrees.ScalarColumnMap
object column = columnMapProperties.GetValue(i);
AssertNonNullAndOfType(column, "System.Data.Entity.Core.Query.InternalTrees.ScalarColumnMap");
string colName = (string)GetProperty(column, "Name");
// can be used for more advanced bingings
// get internal int ScalarColumnMap.ColumnPos;
object columnPositionOfAProperty = GetProperty(column, "ColumnPos");
AssertNonNullAndOfType(columnPositionOfAProperty, "System.Int32");
propertyPositions[(int)columnPositionOfAProperty] = colName;
}
return propertyPositions;
}
static object GetProperty(object obj, string propName)
{
PropertyInfo prop = obj.GetType().GetProperty(propName, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop == null) throw EFChangedException();
return prop.GetValue(obj, new object[0]);
}
static object GetField(object obj, string fieldName)
{
FieldInfo field = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
if (field == null) throw EFChangedException();
return field.GetValue(obj);
}
static void AssertNonNullAndOfType(object obj, string fullName)
{
if (obj == null) throw EFChangedException();
string typeFullName = obj.GetType().FullName;
if (typeFullName != fullName) throw EFChangedException();
}
static InvalidOperationException EFChangedException()
{
return new InvalidOperationException("Entity Framework internals has changed, please review and fix reflection code");
}