2012-02-17 15 views
2

SQLの生成がToTraceString()で返される列の正確な順序を予測するか選択することができますか?EF ToTraceString SQLの生成結果の列の順序

IQueryableにはToTraceString()を使用して、結果の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> ...私のテーブル構造と一致するように生成されたSQLを必要としますWebサーバー上で列挙可能なToList()を取得しても何の問題もなく、SQLへの送り返しは何らかの一括挿入(EFはサポートしていません。 )私のクエリはかなりの量の行を返すので、私はストアドプロシージャを使いたくありません。私は意味...おかげ

答えて

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"); 
} 
0

this questionへの受け入れ答えはToTraceStringによって生成されたSQL()で表示されるエンティティタイプの様々なプロパティを注文するかを把握する方法について説明2つのリンクが含まれているを作る

希望。この情報を使用すると、生の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 
関連する問題