问题
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