16

値の配列が与えられたので、これらの値に基づくプロパティを持つ匿名オブジェクトを作成したいと思います。プロパティ名は、配列内の値のインデックスである"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ステートメントを実行する既存のメソッドのセットがあります。メソッドは通常string、sqlステートメント用にaを取りparams object[]、パラメーターがある場合はaを取ります。クエリでパラメータを使用する場合、それらの名前はになります@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を使用して、 Dapperのメソッドをラップおよび公開Query<T>し、既存のメソッドと一貫性のある方法でこれを行います。たとえば、次のようになります。

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にパラメータを渡すための匿名オブジェクトの作成についての私の質問につながります。


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

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プロパティをチェックすると、コマンドに構成されたパラメーターが表示されません。

4

3 に答える 3

15

Dapper を誤用しています。これを行う必要はありません。代わりに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コンストラクターで無名クラスを受け取ることができます。メソッドDynamicParametersを使用して連結できます。AddDynamicParams

さらに、アノン型への厳密な依存関係はありません。Dapper では、具象型をパラメータとして使用できます。例:

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

...

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

Kevin からも同様の質問がありました。POCO のすべてのプロパティを結合するための迅速かつ簡単な方法を探しています-DynamicParametersここでも、魔法のフープ ジャンプを必要とせずに完全に機能します。

于 2011-12-18T06:53:05.657 に答える
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);
    }
}
于 2011-12-13T15:41:20.670 に答える
1

匿名オブジェクトを動的に作成することはできません。しかし、Dapper は動的オブジェクトで動作するはずです。動的オブジェクトをうまく作成するには、 Clayを使用できます。のようなコードを書くことができます。

var person = New.Person();
person["FirstName"] = "Louis";
// person.FirstName now returns "Louis"
于 2011-12-13T16:00:50.667 に答える