2011-08-19 5 views
5

バッチ処理のためにSql Server 2k8でテーブル値パラメータを使用し始めました。私はこの機能が非常に好きで、長い間待ってから感じています。.NetのReflectionは、User Defined TypeNameを見て動的にテーブル値付きパラメータ/ SqlMetaData []オブジェクトを構築できますか?

しかし、.NetコードからTVPを渡すには、SQLMetaData []を構築してループ内の値を埋めるのが大変です。

Synchronizationの.NetコードのSql ServerおよびSQLMetaData []オブジェクトにユーザー定義型を保持する方法のメンテナンスは、どのようにして避けてください。 SQLで型定義を変更すると、.NETの巨大なコードでその型をどこで使用したのかを簡単に知る方法がありません。

Can .Net Reflectionは、ユーザー定義型の名前を指定してオブジェクト配列を提供することによってデータを埋め込むことによって、SQLMetadataを構築するプログラマーを救助することができます。

は、この例を考えてみましょう:あなたのテーブルには100個の列を持っている場合

SqlMetaData[] tvp_TradingAllocationRule = new SqlMetaData[13]; 
try 
{ 
    tvp_TradingAllocationRule[0] = new SqlMetaData("ID", SqlDbType.UniqueIdentifier); 
    tvp_TradingAllocationRule[1] = new SqlMetaData("Name", SqlDbType.VarChar, 255); 
    tvp_TradingAllocationRule[2] = new SqlMetaData("Description", SqlDbType.VarChar, -1); 
    tvp_TradingAllocationRule[3] = new SqlMetaData("Enabled", SqlDbType.Bit); 
    tvp_TradingAllocationRule[4] = new SqlMetaData("Category", SqlDbType.VarChar, 255); 
    tvp_TradingAllocationRule[5] = new SqlMetaData("Custom1", SqlDbType.VarChar, 255); 
    tvp_TradingAllocationRule[6] = new SqlMetaData("Custom2", SqlDbType.VarChar, 255); 
    tvp_TradingAllocationRule[7] = new SqlMetaData("Custom3", SqlDbType.VarChar, 255); 
    tvp_TradingAllocationRule[8] = new SqlMetaData("CreatedBy", SqlDbType.VarChar, 20); 
    tvp_TradingAllocationRule[9] = new SqlMetaData("CreatedTS", SqlDbType.DateTime); 
    tvp_TradingAllocationRule[10] = new SqlMetaData("ModifiedBy", SqlDbType.VarChar, 20); 
    tvp_TradingAllocationRule[11] = new SqlMetaData("ModifiedTS", SqlDbType.DateTime); 
    tvp_TradingAllocationRule[12] = new SqlMetaData("IsFactory", SqlDbType.Bit); 
} 
catch (Exception ex) 
{ 
    throw new Exception("Error Defining the tvp_TradingActionCondition in .Net" + ex.Message); 
} 

foreach (TradingRuleMetadata ruleMetadata in updatedRules) 
{ 
    SqlDataRecord tradingAllocationRule = new SqlDataRecord(tvp_TradingAllocationRule); 
    try 
    { 
     tradingAllocationRule.SetGuid(0, ruleMetadata.ID); 
     tradingAllocationRule.SetString(1, ruleMetadata.Name); 
     tradingAllocationRule.SetString(2, ruleMetadata.Description); 
     tradingAllocationRule.SetBoolean(3, ruleMetadata.Enabled); 
     tradingAllocationRule.SetString(4, ruleMetadata.Category); 
     tradingAllocationRule.SetString(5, ruleMetadata.Custom1); 
     tradingAllocationRule.SetString(6, ruleMetadata.Custom2); 
     tradingAllocationRule.SetString(7, ruleMetadata.Custom3); 
     tradingAllocationRule.SetString(8, ruleMetadata.CreatedBy); 
     tradingAllocationRule.SetDateTime(9, ruleMetadata.CreatedDate); 
     tradingAllocationRule.SetString(10, ruleMetadata.ModifiedBy); 
     tradingAllocationRule.SetDateTime(11, ruleMetadata.ModifiedDate); 
     tradingAllocationRule.SetBoolean(12, ruleMetadata.IsFactory); 
     tvp_TradingAllocationRuleRecords.Add(tradingAllocationRule); 
    } 
    catch (Exception ex) 
    { 

    } 
} 

は今、あなたのコードを想像してみてください。

+0

私の答えを削除しましたが、あまり役に立ちません。 .net –

+0

の動的データタイプを調べたい場合は、現在使用しているコードのサンプルを表示できますか? – svick

+0

@svic:サンプルコードを投稿しました... – vinayvasyani

答えて

0

コードサンプルを与えるのに十分ではありませんが、このようなことをするには別の.NET実行可能ファイルを作成してSQLメタデータを読み込んでヘルパークラスを生成するようなことをします(あなたの例によく似ています)各UDTごとにコード生成の利点は、実行時に少し速いことです。さらに重要なことは、手書きで書かれたかのようにソースコードを読んだり読んだりすることができることです。また、特に部分キーワードが存在するため、特に難しいことではありません。

3

これは反射を使用して行うことができます。まず、名前と長さのデフォルト値を上書きする方法が必要です。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
class LengthAttribute : Attribute 
{ 
    private readonly int m_length; 
    public int Length 
    { 
     get { return m_length; } 
    } 

    public LengthAttribute(int length) 
    { 
     m_length = length; 
    } 
} 

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
class ColumnNameAttribute : Attribute 
{ 
    private readonly string m_name; 
    public string Name 
    { 
     get { return m_name; } 
    } 

    public ColumnNameAttribute(string name) 
    { 
     m_name = name; 
    } 
} 

そして、あなたのタイプにそれらを使用する:

class TradingRuleMetadata 
{ 
    public Guid ID { get; set; } 

    public string Name { get; set; } 

    [Length(-1)] 
    public string Description { get; set; } 

    public bool Enabled { get; set; } 

    public string Category { get; set; } 

    public string Custom1 { get; set; } 

    public string Custom2 { get; set; } 

    public string Custom3 { get; set; } 

    [Length(20)] 
    public string CreatedBy { get; set; } 

    [ColumnName("CreatedTS")] 
    public DateTime CreatedDate { get; set; } 

    [Length(20)] 
    public string ModifiedBy { get; set; } 

    [ColumnName("ModifiedTS")] 
    public DateTime ModifiedDate { get; set; } 

    public bool IsFactory { get; set; } 
} 

次にあなたがSqlDataRecordのコレクションにこのタイプのコレクションをマップする方法を作成することができ、Attribute Sを定義することを行うために、

private static readonly Dictionary<Type, SqlDbType> SqlDbTypes = 
    new Dictionary<Type, SqlDbType> 
    { 
     { typeof(Guid), SqlDbType.UniqueIdentifier }, 
     { typeof(string), SqlDbType.VarChar }, 
     { typeof(bool), SqlDbType.Bit }, 
     { typeof(DateTime), SqlDbType.DateTime } 
    }; 

static IList<SqlDataRecord> GetDataRecords<T>(IEnumerable<T> data) 
{ 
    Type type = typeof(T); 

    var properties = type.GetProperties(); 

    SqlMetaData[] metaData = new SqlMetaData[properties.Length]; 
    try 
    { 
     for (int i = 0; i < properties.Length; i++) 
     { 
      var property = properties[i]; 

      string name = property.Name; 
      var columnNameAttribute = GetAttribute<ColumnNameAttribute>(property); 
      if (columnNameAttribute != null) 
       name = columnNameAttribute.Name; 

      var dbType = SqlDbTypes[property.PropertyType]; 

      if (dbType == SqlDbType.VarChar) 
      { 
       int length = 255; 

       var lengthAttribute = GetAttribute<LengthAttribute>(property); 
       if (lengthAttribute != null) 
        length = lengthAttribute.Length; 

       metaData[i] = new SqlMetaData(name, dbType, length); 
      } 
      else 
       metaData[i] = new SqlMetaData(name, dbType); 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(); 
    } 

    var records = new List<SqlDataRecord>(); 
    foreach (T item in data) 
    { 
     SqlDataRecord record = new SqlDataRecord(metaData); 
     try 
     { 
      var values = properties.Select(p => p.GetValue(item, null)).ToArray(); 
      record.SetValues(values); 
      records.Add(record); 
     } 
     catch (Exception ex) 
     { 

     } 
    } 
    return records; 
} 

static T GetAttribute<T>(PropertyInfo property) 
{ 
    return (T)property.GetCustomAttributes(typeof(T), true).SingleOrDefault(); 
} 

このコードは非常に多くのリフレクションを使用しているため、遅すぎる可能性があります。そのような場合は、何らかのキャッシングを実装する必要があります。これを行う1つの方法は、Expressionを作成して、すべての作業を行い、デリゲート(.Net 4のみ、BlockExpressionが必要なため)にコンパイルすることです。

また、いくつかのプロパティなどを無視する必要があるため、実際の要件はさらに複雑になる可能性があります。しかし、それは簡単に追加できます。

関連する問題