Pass C# bool as parameter to Oracle using Dapper

纵然是瞬间 提交于 2019-12-24 09:49:06

问题


I'm trying to pass a bool as a parameter to Oracle using Dapper, translating to a 1/0 field on the database, like this:

public class Customer
{
    public bool Active { get; set; }
}
static void InsertCustomer()
{
    var customer = connect.QueryFirst<Customer>("select 1 active from dual"); // this works
    connect.Execute("insert into customers(active) values(:active)", customer); // this doesn't
}

But this throws an exception:

System.ArgumentException: 'Value does not fall within the expected range.'

I know I can create another property public int ActiveInt => Active ? 1 : 2; but I would like to keep my POCO classes as clean as possible, especially because the properties need to be public for Dapper to use them as parameters.

I tried to create a bool type handler, but it only works for query columns, not parameters: https://github.com/StackExchange/Dapper/issues/303

I also need to pass the whole object as parameter, so converting when passing the parameter isn't possible.

Is there a way to do that?


回答1:


I use Dapper.SqlMapper.AddTypeMap(Type, DbType) method.

public class Customer
{
    public bool Active { get; set; }
}

class Program : IDisposable
{
    private readonly DbConnection _connection;

    public Program()
    {
        _connection = DbOpen();
    }

    static void Main(string[] args)
    {
        SqlMapper.AddTypeMap(typeof(bool), DbType.Int32);

        using (var program = new Program())
        {
            program.Run();
        }
    }

    private void Run()
    {
        _connection.Execute($"INSERT INTO customers ( active ) VALUES (:Activate)", new { Activate = true });
        _connection.Execute($"INSERT INTO customers ( active ) VALUES (:Activate)", new { Activate = false });

        var customers = new List<Customer>()
        {
            new Customer() {Active = true},
            new Customer() {Active = false}
        };
        _connection.Execute($"INSERT INTO customers ( active ) VALUES (:{nameof(Customer.Active)})", customers);

        var results = _connection.Query<Customer>("SELECT * FROM customers");
        foreach (var customer results)
        {
            Console.WriteLine($"{nameof(Customer.Active)} is {customer.Active}");
        }
    }

    private static DbConnection DbOpen()
    {
        var connectionSetting = ConfigurationManager.ConnectionStrings["oracle"];
        var dbFactory = DbProviderFactories.GetFactory(connectionSetting.ProviderName);
        var conn = dbFactory.CreateConnection();
        conn.ConnectionString = connectionSetting.ConnectionString;
        conn.Open();
        return conn;
    }

    public void Dispose()
    {
        _connection?.Dispose();
    }
}



回答2:


I do not have an Oracle DB to play with, however, with what i see online and what i know of dapper, you can try converting your object into a dapper dynamic parameters object and insert the : that is required by oracle into the front of each parameter name. You can do that using this extension method i put together:

public static class ParameterExtensions
  {
    /// <summary>
    /// Extension method that converts any single dimensional object into Dapper's Dynamic Parameters
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="incoming"></param>
    /// <param name="allowNulls">Provide true to allow nulls to be mapped</param>
    /// <returns></returns>
    public static DynamicParameters ConvertToDynamicParameters<T>(this T incoming, bool allowNulls = false)
    {
      DynamicParameters dynamicParameters = new DynamicParameters();
      foreach (PropertyInfo property in incoming.GetType().GetProperties())
      {
        object value = GetPropValue(incoming, property.Name);
        if (value != null || allowNulls) dynamicParameters.Add($":{property.Name}", value);
      }
      return dynamicParameters;
    }

    private static object GetPropValue(object src, string propName)
    {
      return src.GetType().GetProperty(propName)?.GetValue(src, null);
    }
  }

This is what your implementation would change to:

public class Customer
{
  public bool Active { get; set; }
}
static void InsertCustomer()
{
  var customer = connect.QueryFirst<Customer>("select 1 active from dual"); // this works
  connect.Execute(@"insert into customers(active) values(:active)", customer.ConvertToDynamicParameters()); // this doesn't
}

Please let me know if this worked for you.

**Note: You will need to make the parameters case match in the query and on your object. For example on your Customer object you have Customer.Active this name must match :active.



来源:https://stackoverflow.com/questions/42365865/pass-c-sharp-bool-as-parameter-to-oracle-using-dapper

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!