Commit bce25285 authored by Sam's avatar Sam

Merge pull request #15 from greygeek/master

Added postresql support for Insert to return primary key of inserted row.
parents e9d167e9 d57970fb
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Threading; using System.Threading;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Dapper;
namespace Dapper.Contrib.Extensions namespace Dapper.Contrib.Extensions
{ {
...@@ -25,6 +26,11 @@ public interface IProxy ...@@ -25,6 +26,11 @@ public interface IProxy
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>(); 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 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) private static IEnumerable<PropertyInfo> KeyPropertiesCache(Type type)
{ {
...@@ -57,11 +63,22 @@ private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type) ...@@ -57,11 +63,22 @@ private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type)
return pis; return pis;
} }
var properties = type.GetProperties(); var properties = type.GetProperties().Where(IsWriteable);
TypeProperties[type.TypeHandle] = properties; TypeProperties[type.TypeHandle] = properties;
return properties; return properties;
} }
public static bool IsWriteable(PropertyInfo pi)
{
object[] attributes = pi.GetCustomAttributes(typeof (WriteAttribute), false);
if (attributes.Length == 1)
{
WriteAttribute write = (WriteAttribute) attributes[0];
return write.Write;
}
return true;
}
/// <summary> /// <summary>
/// Returns a single entity by a single id from table "Ts". T must be of interface type. /// Returns a single entity by a single id from table "Ts". T must be of interface type.
/// Id must be marked with [Key] attribute. /// Id must be marked with [Key] attribute.
...@@ -154,8 +171,7 @@ private static string GetTableName(Type type) ...@@ -154,8 +171,7 @@ private static string GetTableName(Type type)
var name = GetTableName(type); var name = GetTableName(type);
var sb = new StringBuilder(null); var sbColumnList = new StringBuilder(null);
sb.AppendFormat("insert into {0} (", name);
var allProperties = TypePropertiesCache(type); var allProperties = TypePropertiesCache(type);
var keyProperties = KeyPropertiesCache(type); var keyProperties = KeyPropertiesCache(type);
...@@ -164,25 +180,22 @@ private static string GetTableName(Type type) ...@@ -164,25 +180,22 @@ private static string GetTableName(Type type)
for (var i = 0; i < allPropertiesExceptKey.Count(); i++) for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
{ {
var property = allPropertiesExceptKey.ElementAt(i); var property = allPropertiesExceptKey.ElementAt(i);
sb.Append(property.Name); sbColumnList.Append(property.Name);
if (i < allPropertiesExceptKey.Count() - 1) if (i < allPropertiesExceptKey.Count() - 1)
sb.Append(", "); sbColumnList.Append(", ");
} }
sb.Append(") values (");
var sbParameterList = new StringBuilder(null);
for (var i = 0; i < allPropertiesExceptKey.Count(); i++) for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
{ {
var property = allPropertiesExceptKey.ElementAt(i); var property = allPropertiesExceptKey.ElementAt(i);
sb.AppendFormat("@{0}", property.Name); sbParameterList.AppendFormat("@{0}", property.Name);
if (i < allPropertiesExceptKey.Count() - 1) if (i < allPropertiesExceptKey.Count() - 1)
sb.Append(", "); sbParameterList.Append(", ");
} }
sb.Append(") "); ISqlAdapter adapter = GetFormatter(connection);
connection.Execute(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout); int id = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), sbParameterList.ToString(), keyProperties, entityToInsert);
//NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE return id;
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout);
return (int)r.First().id;
} }
/// <summary> /// <summary>
...@@ -203,7 +216,7 @@ private static string GetTableName(Type type) ...@@ -203,7 +216,7 @@ private static string GetTableName(Type type)
var type = typeof(T); var type = typeof(T);
var keyProperties = KeyPropertiesCache(type); var keyProperties = KeyPropertiesCache(type);
if (keyProperties.Count() == 0) if (!keyProperties.Any())
throw new ArgumentException("Entity must have at least one [Key] property"); throw new ArgumentException("Entity must have at least one [Key] property");
var name = GetTableName(type); var name = GetTableName(type);
...@@ -264,6 +277,13 @@ private static string GetTableName(Type type) ...@@ -264,6 +277,13 @@ private static string GetTableName(Type type)
return deleted > 0; 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
{ {
...@@ -440,4 +460,63 @@ public class KeyAttribute : Attribute ...@@ -440,4 +460,63 @@ public class KeyAttribute : Attribute
{ {
} }
[AttributeUsage(AttributeTargets.Property)]
public class WriteAttribute : Attribute
{
public WriteAttribute(bool write)
{
Write = 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