Как создать анонимный объект с динамическим определением имен свойств? - PullRequest
16 голосов
/ 13 декабря 2011

Учитывая массив значений, я хотел бы создать анонимный объект со свойствами, основанными на этих значениях. Имена свойств будут просто "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 и params object[] для параметров, если таковые имеются. Понятно, что если в запросе используются параметры, они будут называться @p0, @p1, @p2, etc..

* 1 028 * Пример:
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.


Добавление кода с использованием класса 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);

создает исключение в строке 581 файла Daq SqlMapper.cs:

using (var reader = cmd.ExecuteReader())

и исключением является SqlException:

Необходимо объявить скалярную переменную "@ p0".

и проверка свойства cmd.Parameters не показывает параметров, настроенных для команды.

Ответы [ 3 ]

14 голосов
/ 18 декабря 2011

Вы неправильно используете 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});

У Кевина был похожий вопрос: В поисках быстрого и простого способа объединить все свойства в POCO - DynamicParameters отлично работает и здесь, без необходимости магических прыжковых прыжков.

5 голосов
/ 13 декабря 2011

Не совсем анонимный объект, но как насчет реализации DynamicObject , который возвращает значения для p1 ... pn на основе значений в массиве?Будет ли это работать с 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);
    }
}
1 голос
/ 13 декабря 2011

Вы не можете динамически создавать анонимные объекты.Но Dapper должен работать с динамическим объектом.Для создания динамических объектов хорошим способом вы можете использовать Clay .Это позволяет вам писать код как

var person = New.Person();
person["FirstName"] = "Louis";
// person.FirstName now returns "Louis"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...