2011-12-13 5 views
15

値の配列が与えられたら、これらの値に基づいてプロパティを持つ匿名オブジェクトを作成したいと思います。プロパティ名は、単に"pN"となります。ここで、Nは配列内の値のインデックスです。プロパティ名が動的に決定された匿名オブジェクトを作成する方法は?

例えば、

object[] values = { 123, "foo" };

与えられた私はこれを行うには、私は考えることができる唯一の方法は、使用することであろう匿名オブジェクト

new { p0 = 123, p1 = "foo" };

を作成したいですswitchまたはifをサポートするには、合理的な数のパラメータまで連鎖しますが、これを行うためのよりエレガントな方法があるかどうか疑問に思っていました。

object[] parameterValues = new object[] { 123, "foo" }; 
dynamic values = null; 

switch (parameterValues.Length) 
{ 
    case 1: 
     values = new { p0 = parameterValues[0] }; 
     break; 
    case 2: 
     values = new { p0 = parameterValues[0], p1 = parameterValues[1] };  
     break; 
    // etc. up to a reasonable # of parameters 
} 

背景

私は、データベースに対してSQL文を実行する方法の既存のセットを持っています。これらのメソッドは、通常、SQL文の場合はstring、パラメータがある場合はparams object[]となります。クエリがパラメータを使用する場合、その名前は@p0, @p1, @p2, etc.となります。

例:

このように呼ばれることになる
public int ExecuteNonQuery(string commandText, CommandType commandType, params object[] parameterValues) { .... } 

db.ExecuteNonQuery("insert into MyTable(Col1, Col2) values (@p0, @p1)", CommandType.Text, 123, "foo"); 

今、私はDapperののQuery<T>メソッドをラップし、公開するために、このクラス内Dapperを使用したい、としてそう既存の方法、例えば

public IEnumerable<T> ExecuteQuery<T>(string commandText, CommandType commandType, params object[] parameterValues) { .... } 

が、DapperののQuery<T>方法は匿名オブジェクトのパラメータ値を取ります:何かのように

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid }); 

Dapperのにパラメータを渡すために匿名のオブジェクトを作成する方法について、私の質問につながります。


@Paolo Tedescoの要求に従ってDynamicParameterクラスを使用してコードを追加します。

string sql = "select * from Account where Id = @p0 and username = @p1"; 
dynamic values = new DynamicParameter(123, "test"); 
var accounts = SqlMapper.Query<Account>(connection, sql, values); 

はDapperののSqlMapper.csファイルの行581で例外がスローされます:

using (var reader = cmd.ExecuteReader()) 

と例外がSqlException次のとおりです。

はスカラー変数 "@ P0" を宣言する必要があります。

をチェックし、cmd.Parametersプロパティをチェックすると、コマンドに設定されたパラメータが表示されません。

+0

はい、DynamicParameterを誤って使用しています(243行目を参照)。http://code.google.com/p/dapper-dot-net/source/browse/Tests/Tests.cs –

+0

また、IDynamicParamtersは絶対柔軟性。ダッパの利益のために、あなたは一種の学習体験として、無名のタイプを焼く必要はありませんが、努力する価値はありません。特に、あなたが本当にemitを使いたければ、ICollectionから強力な型を作ることができます。 –

答えて

5

匿名のオブジェクトではありませんが、配列内の値に基づいてp1 ... pnの値を返すDynamicObjectを実装するとどうなりますか? Dapperと一緒に使えますか?

例:

using System; 
using System.Dynamic; 
using System.Text.RegularExpressions; 

class DynamicParameter : DynamicObject { 

    object[] _p; 

    public DynamicParameter(params object[] p) { 
     _p = p; 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) { 
     Match m = Regex.Match(binder.Name, @"^p(\d+)$"); 
     if (m.Success) { 
      int index = int.Parse(m.Groups[1].Value); 
      if (index < _p.Length) { 
       result = _p[index]; 
       return true; 
      } 
     } 
     return base.TryGetMember(binder, out result); 
    } 

} 

class Program { 
    static void Main(string[] args) { 
     dynamic d1 = new DynamicParameter(123, "test"); 
     Console.WriteLine(d1.p0); 
     Console.WriteLine(d1.p1); 
    } 
} 
+0

+1、ありがとう、これは素晴らしいですが、残念ながらDapperはそれが好きではありません:(それはまったくパラメータなしでdbコマンドを実行しようとすることに終わっています - なぜ、まだわかりませんが、パラメータ値としての 'DynamicParameter'インスタンス –

+0

@adrift:あなたの問題を示す小さなコードサンプルを投稿できますか? –

+0

は、' DynamicParameter'を使用しようとしたときに生成された例外を示すコードを含むように質問を編集しました。 –

1

あなたが動的に匿名のオブジェクトを作成することはできません。しかし、Dapperは動的オブジェクトで動作する必要があります。良い方法で動的オブジェクトを作成するには、Clayを使用できます。それはあなたがDapperのを悪用している

var person = New.Person(); 
person["FirstName"] = "Louis"; 
// person.FirstName now returns "Louis" 
12

のようなコードを書くことができます、あなたがIDynamicParametersを実装したり、特定の非常に柔軟なDynamicParametersクラスを使用するか代わりに、これを実行する必要はありません。特に

string sql = "select * from Account where Id = @id and username = @name"; 
var values = new DynamicParameters(); 
values.Add("id", 1); 
values.Add("name", "bob"); 
var accounts = SqlMapper.Query<Account>(connection, sql, values); 

DynamicParametersは、コンストラクタで匿名クラスで取ることができます。 AddDynamicParamsメソッドを使用してconcatをDynamicParametersにすることができます。

さらに、anonタイプには厳密な依存関係はありません。 Dapperのはのparamsなどのように具体的なタイプのためにできるようになります:

class Stuff 
{ 
    public int Thing { get; set; } 
} 

... 

cnn.Execute("select @Thing", new Stuff{Thing = 1}); 

ケビンは、同様の質問だった:Looking for a fast and easy way to coalesce all properties on a POCOからDynamicParametersはマジックフープジャンプを必要とせずにも完璧にここに動作しますが。

関連する問題