2017-12-25 11 views
1

実行時にストアドプロシージャからDataTableの列を取得しています。コードは次のようになります。クラスのプロパティを作成し、実行時にプロジェクトに追加します

var parkDataTable = new DataTable("tmp"); 
... 
SqlCommand cmd = new SqlCommand("FooStoredProcedure", db.Database.Connection as 
    SqlConnection, transaction.UnderlyingTransaction as SqlTransaction); 
cmd.CommandType = CommandType.StoredProcedure;  
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); 
parkDataTable.Load(dr); 

私の列には、列名に日付を追加することでさまざまな名前を付けることができます。たとえば、カラム名が2017-09-01_FactPark、次回のカラムが2017-10-01_FactParkになります。 、列に以下の画像を参照してください。

enter image description here

私は、実行時に列の列名と数量について知ることができます。

それは、実行時にプロパティとして上記の列を持つクラスを作成し、通常の方法のように、これらのプロパティにそれらを投影することが可能です:

public IQueryable<EmployeeDTO> GetEmployees() 
{ 
    return db.Employees 
     .Select(employee => new EmployeeDTO 
     { 
      ID = employee.ID,      
      FirstName = employee.PriceNumber, 
      LastName = employee.PriceDate           
     }).AsQueryable(); 
} 

だから私の目標はDataTableからプロパティを持つクラスを作成することですプロパティを持つクラスに列DataTableを投影します。

実行時にプロパティを作成して、クラスDataTableの新しく作成されたプロパティに列を投影することは可能ですか?

+2

* 2017-0901_FactPark *、* 2017-10-01_FactPark * ...誰かが正規化を必要とします... – JohnyL

+0

あなたは許可されていないか、または許可されていませんか? :) – JohnyL

+0

@JohnyL列名はストアドプロシージャのSELECT文によって作成され、このSELECT文を変更することはできません。 – StepUp

答えて

3

クラスの形状を動的に構成する1つの方法は、DynamicObjectクラスです。その値でプロパティを設定およびフェッチする独自の動的クラスを作成できます。

今のところ、私たちのダイナミックなクラスを実装してみましょう:

using System.Dynamic; 

class Dynamo : DynamicObject 
{ 
    private Dictionary<string, object> items = new Dictionary<string, object>(); 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     return items.TryGetValue(binder.Name, out result); 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     items[binder.Name] = value; 
     return true; 
    } 

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) 
    { 
     string propName = indexes[0] as string; 
     items[propName] = value; 
     return true; 
    } 

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) 
    { 
     string propName = indexes[0] as string; 
     return items.TryGetValue(propName, out result); 
    } 

    public override IEnumerable<string> GetDynamicMemberNames() 
    { 
     return items.Keys; 
    } 
} 

私たちがここに持っているもの:

  1. items辞書を。任意の値を保存し、名前で取得できます。
  2. TryGetMember()/TrySetMember()の方法。このグループでは、Dot-Propertyの表記で値を設定/取得できます。Class.Property
  3. TrySetIndex()/TryGetIndex()の方法。このグループでは、Indexerという値を設定/取得することができます。Class[varHoldingPropName]またはClass["propName"]です。
  4. GetDynamicMemberNames()メソッド。すべてのプロパティ名を取得できます。プロパティ名を設定するために

Indexerはあなたの変数を評価する一方Dot-Property表記とバインダーは、識別子名としてあなたプロパティ名を使用しますので、あなたは、Indexer表記を使用する必要があります。

static void UseDynamicObject() 
{ 

    var colorProperty = "Color"; 
    var ageProperty = "Age"; 

    dynamic dynamo = new Dynamo(); 
    dynamo.colorProperty = "red"; 
    dynamo[ageProperty] = 20; 

    // DOT-PROPERTY NOTATION 
    // Error: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 
    // 'Dynamo' does not contain a definition for 'Color'. 
    Console.WriteLine(dynamo.Color); 
    // The property used to retrieve value "red" is "colorProperty" rather "Color". 
    Console.WriteLine(dynamo.colorProperty); 

    // INDEXER NOTATION 
    // We can use either variable or literal name of the property, 
    // so these two lines are equivalent. 
    Console.WriteLine(dynamo[ageProperty]); 
    Console.WriteLine(dynamo["Age"]); 

} 

ロジックあなたはSqlDataReaderから列の名前を取得し、それらを動的オブジェクトに設定するために使用することができます。ここで

は、SqlDataReaderのと私たちのダイナミックなクラスを使用しての一つの可能​​な変種です:

static void Main(string[] args) 
{ 

    var data = new List<dynamic>(); 
    List<string> cols = default; 

    using (var conn = new SqlConnection(connStr)) 
    { 
     conn.Open(); 
     using (var comm = new SqlCommand("SELECT * FROM dbo.Client", conn)) 
     { 
      using (var reader = comm.ExecuteReader()) 
      { 
       // Get columns names 
       cols = Enumerable.Range(0, reader.FieldCount) 
         .Select(i => reader.GetName(i)).ToList(); 
       while (reader.Read()) 
       { 
        dynamic obj = new Dynamo(); 
        cols.ForEach(c => obj[c] = reader[c]); 
        data.Add(obj); 
       } 
      } 
     } 
    } 


    /* OUTPUT DATA */ 

    // To get columns names, you can: 
    // 1) use ready "cols" variable 
    // 2) use "GetDynamicMemberNames()" on first object: 
    // IEnumerable<string> cols = data[0].GetDynamicMemberNames(); 
    foreach (var obj in data) 
    { 
     Console.WriteLine(String.Join(", ", cols.Select(c => $"{c} = {obj[c]}"))); 
    } 

    // Output: 
    // ClientId = 1, ClientName = Client1 
    // ClientId = 2, ClientName = Client2 

} 
+0

テストする機会はありませんが、私はあなたに信じています:) – StepUp

+1

@StepUp徹底的にテストしたので、それはうまく動作します) – JohnyL

+0

@JohnyL nice、私は2ヶ月前に同じ質問をしていましたが、 'ExpandoObjects'を使って? – Yollo

関連する問題