Commit d57970fb authored by David Chell's avatar David Chell

Removed POSTGRESQL define and added SqlAdapter dictionary to handle variances in DBMSs

parent ee98aa53
#define POSTGRESQL
using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
......@@ -11,6 +9,7 @@
using System.Reflection.Emit;
using System.Threading;
using System.Runtime.CompilerServices;
using Dapper;
namespace Dapper.Contrib.Extensions
{
......@@ -27,6 +26,11 @@ public interface IProxy
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary = new Dictionary<string, ISqlAdapter>() {
{"sqlconnection", new SqlServerAdapter()},
{"npgsqlconnection", new PostgresAdapter()}
};
private static IEnumerable<PropertyInfo> KeyPropertiesCache(Type type)
{
......@@ -167,60 +171,30 @@ private static string GetTableName(Type type)
var name = GetTableName(type);
var sb = new StringBuilder(null);
sb.AppendFormat("insert into {0} (", name);
var sbColumnList = new StringBuilder(null);
var allProperties = TypePropertiesCache(type);
var allProperties = TypePropertiesCache(type);
var keyProperties = KeyPropertiesCache(type);
var allPropertiesExceptKey = allProperties.Except(keyProperties);
for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
{
var property = allPropertiesExceptKey.ElementAt(i);
sb.Append(property.Name);
sbColumnList.Append(property.Name);
if (i < allPropertiesExceptKey.Count() - 1)
sb.Append(", ");
sbColumnList.Append(", ");
}
sb.Append(") values (");
for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
var sbParameterList = new StringBuilder(null);
for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
{
var property = allPropertiesExceptKey.ElementAt(i);
sb.AppendFormat("@{0}", property.Name);
sbParameterList.AppendFormat("@{0}", property.Name);
if (i < allPropertiesExceptKey.Count() - 1)
sb.Append(", ");
sbParameterList.Append(", ");
}
sb.Append(") ");
long id = 0;
#if POSTGRESQL
if (keyProperties.Count() > 0)
{
sb.Append(" RETURNING ");
for (var i = 0; i < keyProperties.Count(); i++)
{
var property = keyProperties.ElementAt(i);
sb.Append(property.Name);
if (i < keyProperties.Count() - 1)
sb.Append(", ");
}
var r = connection.Query(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
// Return the key py assinging the corresponding property in the object - by product is that it supports compound primary keys
foreach (var p in keyProperties)
{
var value = ((IDictionary<string, object>) r.First())[p.Name.ToLower()];
p.SetValue(entityToInsert, value, null);
if (id == 0)
id = Convert.ToInt64(value);
}
}
else
connection.Execute(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
#else
connection.Execute(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
//NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout);
id = (int)r.First().id;
#endif
ISqlAdapter adapter = GetFormatter(connection);
int id = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), sbParameterList.ToString(), keyProperties, entityToInsert);
return id;
}
......@@ -242,7 +216,7 @@ private static string GetTableName(Type type)
var type = typeof(T);
var keyProperties = KeyPropertiesCache(type);
if (keyProperties.Count() == 0)
if (!keyProperties.Any())
throw new ArgumentException("Entity must have at least one [Key] property");
var name = GetTableName(type);
......@@ -303,8 +277,15 @@ private static string GetTableName(Type type)
return deleted > 0;
}
public static ISqlAdapter GetFormatter(IDbConnection connection)
{
string name = connection.GetType().Name.ToLower();
if (!AdapterDictionary.ContainsKey(name))
return new SqlServerAdapter();
return AdapterDictionary[name];
}
class ProxyGenerator
class ProxyGenerator
{
private static readonly Dictionary<Type, object> TypeCache = new Dictionary<Type, object>();
......@@ -489,3 +470,53 @@ public WriteAttribute(bool write)
public bool Write { get; private set; }
}
}
public interface ISqlAdapter
{
int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
}
public class SqlServerAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
string cmd = String.Format("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
connection.Execute(cmd, entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
//NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout);
return (int)r.First().id;
}
}
public class PostgresAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
sb.Append(" RETURNING ");
bool first = true;
foreach(var property in keyProperties)
{
if (!first)
sb.Append(", ");
first = false;
sb.Append(property.Name);
}
var results = connection.Query(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
// Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys
int id = 0;
foreach (var p in keyProperties)
{
var value = ((IDictionary<string, object>)results.First())[p.Name.ToLower()];
p.SetValue(entityToInsert, value, null);
if (id == 0)
id = Convert.ToInt32(value);
}
return id;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment