Skip to content

Loading…

Give values for key attributes v2. #57

Closed
wants to merge 3 commits into from

2 participants

@haeal

Fixed up the line endings problem (hopefully).
Also added another bugfix for postgres using the Get extension.

haeal added some commits
@haeal haeal Can now insert an object with a [Key] attribute without needing a def…
…ault value on the DB column.

Added an optional parameter for specifying that the value provided with the [Key] Parameter should be used when performing the insert.  This allows primary key indication (for updates) on tables with no default value for the primary key.

Added a test for the feature added above.  It only runs for Postgres, as SqlCe gets angry about no IDENTITY on Id.

Added the ability to run the tests against different databases for Dapper.Contrib, and implemented running against a Postgres database.  As there is no 'in memory' Postgres feature, so the user will have to set up their own copy.  Due to that, it's commented out by default.
4b9e7fa
@haeal haeal Clean up of constant strings, and removing a table create that is not…
… used.
9ecaf7a
@haeal haeal Fixed up the Get method for Postgres by failing over to a case insens…
…itive property fetch.

By default Postgres lowercases all table and column names not encased in quotes.  Probably needs a revisit at some time to allow such a feature, but this keeps the backwards compatible possibility of having two same named columns with different case be distinguishable, and failover to insensitive for Postgres.
adcbe45
@NickCraver
Stack Overflow member

Obviously just a little late reviewing this (sorry!), but I'm thinking this may not be effectual after the v3.0 driver changes. I wouldn't merge this as-is because of the breaking change on Insert<T> though - that needs to be a separate discussion and PR.

@NickCraver
Stack Overflow member

This is now being implemented via #352, closing this one out. Thanks for the push to look at this and the work!

@NickCraver NickCraver closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 11, 2012
  1. @haeal

    Can now insert an object with a [Key] attribute without needing a def…

    haeal committed
    …ault value on the DB column.
    
    Added an optional parameter for specifying that the value provided with the [Key] Parameter should be used when performing the insert.  This allows primary key indication (for updates) on tables with no default value for the primary key.
    
    Added a test for the feature added above.  It only runs for Postgres, as SqlCe gets angry about no IDENTITY on Id.
    
    Added the ability to run the tests against different databases for Dapper.Contrib, and implemented running against a Postgres database.  As there is no 'in memory' Postgres feature, so the user will have to set up their own copy.  Due to that, it's commented out by default.
  2. @haeal
  3. @haeal

    Fixed up the Get method for Postgres by failing over to a case insens…

    haeal committed
    …itive property fetch.
    
    By default Postgres lowercases all table and column names not encased in quotes.  Probably needs a revisit at some time to allow such a feature, but this keeps the backwards compatible possibility of having two same named columns with different case be distinguishable, and failover to insensitive for Postgres.
View
8 Dapper.Contrib.Tests/Dapper.Contrib.Tests.csproj
@@ -42,6 +42,12 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Mono.Security">
+ <HintPath>..\packages\Npgsql.2.0.11\lib\Net40\Mono.Security.dll</HintPath>
+ </Reference>
+ <Reference Include="Npgsql">
+ <HintPath>..\packages\Npgsql.2.0.11\lib\Net40\Npgsql.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
@@ -56,8 +62,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Assert.cs" />
+ <Compile Include="PostgresqlTests.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="SqlCeTests.cs" />
<Compile Include="Tests.cs" />
</ItemGroup>
<ItemGroup>
View
41 Dapper.Contrib.Tests/PostgresqlTests.cs
@@ -0,0 +1,41 @@
+using System.Data;
+using Npgsql;
+
+namespace Dapper.Contrib.Tests
+{
+ public class PostgresqlTests : Tests
+ {
+ private bool _setUp;
+ protected override IDbConnection GetOpenConnection()
+ {
+ var conn = new NpgsqlConnection(ConnectionString);
+ conn.Open();
+ return conn;
+ }
+
+ protected override string ConnectionString
+ {
+ get { return "Server=127.0.0.1;Port=5432;User Id=test;Password=testpass;Database=test;"; }
+ }
+
+ public override void SetUpTests()
+ {
+ if (_setUp)
+ return;
+
+ using (var conn = new NpgsqlConnection(ConnectionString))
+ {
+ conn.Open();
+
+ conn.Execute("DROP TABLE IF EXISTS Users");
+ conn.Execute("DROP TABLE IF EXISTS Automobiles");
+ conn.Execute("DROP TABLE IF EXISTS Houses");
+
+ conn.Execute("CREATE TABLE Users (id SERIAL NOT NULL, name text NOT NULL, age integer NOT NULL)");
+ conn.Execute("CREATE TABLE Automobiles (id SERIAL NOT NULL, name text NOT NULL)");
+ conn.Execute("CREATE TABLE Houses (id integer NOT NULL, number integer NOT NULL, road text NOT NULL)");
+ }
+ _setUp = true;
+ }
+ }
+}
View
34 Dapper.Contrib.Tests/Program.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
+using System.Data;
using System.Data.SqlServerCe;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
+using Npgsql;
namespace Dapper.Contrib.Tests
{
@@ -13,39 +15,27 @@ class Program
{
static void Main(string[] args)
{
- Setup();
- RunTests();
- }
+ //Test SqlCe Database.
+ RunTests(new SqlCeTests());
- private static void Setup()
- {
- var projLoc = Assembly.GetAssembly(typeof(Program)).Location;
- var projFolder = Path.GetDirectoryName(projLoc);
+ //If postgresql is set up, uncomment this section. To run this on windows, try http://www.postgresql.org/download/windows/
+ //This assumes you already have a database called test, and a test user with permissions on that database.
+ RunTests(new PostgresqlTests());
- if (File.Exists(projFolder + "\\Test.sdf"))
- File.Delete(projFolder + "\\Test.sdf");
- var connectionString = "Data Source = " + projFolder + "\\Test.sdf;";
- var engine = new SqlCeEngine(connectionString);
- engine.CreateDatabase();
- using (var connection = new SqlCeConnection(connectionString))
- {
- connection.Open();
- connection.Execute(@" create table Users (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null, Age int not null) ");
- connection.Execute(@" create table Automobiles (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null) ");
- }
- Console.WriteLine("Created database");
+ Console.WriteLine("All tests complete! Press any key to exit.");
+ Console.ReadKey();
}
- private static void RunTests()
+ private static void RunTests(Tests tester)
{
- var tester = new Tests();
+ Console.WriteLine("Now testing: " + tester.GetType().Name);
+
foreach (var method in typeof(Tests).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
Console.Write("Running " + method.Name);
method.Invoke(tester, null);
Console.WriteLine(" - OK!");
}
- Console.ReadKey();
}
}
View
61 Dapper.Contrib.Tests/SqlCeTests.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SqlServerCe;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace Dapper.Contrib.Tests
+{
+ class SqlCeTests : Tests
+ {
+ private readonly string _assemblyLocation;
+ private readonly string _projFolder;
+ private const string DatabaseFilename = "Test.sdf";
+ private bool _setUp;
+
+ public SqlCeTests()
+ {
+ _assemblyLocation = Assembly.GetAssembly(GetType()).Location;
+ _projFolder = Path.GetDirectoryName(_assemblyLocation);
+ }
+
+ protected override IDbConnection GetOpenConnection()
+ {
+ var connection = new SqlCeConnection(ConnectionString);
+ connection.Open();
+ return connection;
+ }
+
+ protected override string ConnectionString
+ {
+ get
+ {
+ return string.Format("Data Source = {0}\\{1};", _projFolder, DatabaseFilename);
+ }
+ }
+
+ public override void SetUpTests()
+ {
+ if (_setUp)
+ return;
+
+ string fullPath = Path.Combine(_projFolder, DatabaseFilename);
+ if (File.Exists(fullPath))
+ File.Delete(fullPath);
+ var connectionString = ConnectionString;
+ var engine = new SqlCeEngine(connectionString);
+ engine.CreateDatabase();
+
+ using (var connection = new SqlCeConnection(connectionString))
+ {
+ connection.Open();
+ connection.Execute(@" create table Users (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null, Age int not null) ");
+ connection.Execute(@" create table Automobiles (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null) ");
+ }
+ _setUp = true;
+ }
+ }
+}
View
68 Dapper.Contrib.Tests/Tests.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using System;
using Dapper;
+using Npgsql;
namespace Dapper.Contrib.Tests
@@ -33,17 +34,21 @@ public class Car
public string Name { get; set; }
}
- public class Tests
+ [Table("Houses")]
+ public class Houses
{
- private IDbConnection GetOpenConnection()
- {
- var projLoc = Assembly.GetAssembly(GetType()).Location;
- var projFolder = Path.GetDirectoryName(projLoc);
+ [Key]
+ public int Id { get; set; }
+ public int Number { get; set; }
+ public string Road { get; set; }
+ }
- var connection = new SqlCeConnection("Data Source = " + projFolder + "\\Test.sdf;");
- connection.Open();
- return connection;
- }
+
+ public abstract class Tests
+ {
+ protected abstract IDbConnection GetOpenConnection();
+ protected abstract string ConnectionString { get; }
+ public abstract void SetUpTests();
public void TableName()
{
@@ -52,9 +57,9 @@ public void TableName()
// tests against "Automobiles" table (Table attribute)
connection.Insert(new Car {Name = "Volvo"});
connection.Get<Car>(1).Name.IsEqualTo("Volvo");
- connection.Update(new Car() {Id = 1, Name = "Saab"}).IsEqualTo(true);
+ connection.Update(new Car {Id = 1, Name = "Saab"}).IsEqualTo(true);
connection.Get<Car>(1).Name.IsEqualTo("Saab");
- connection.Delete(new Car() {Id = 1}).IsEqualTo(true);
+ connection.Delete(new Car {Id = 1}).IsEqualTo(true);
connection.Get<Car>(1).IsNull();
}
}
@@ -115,6 +120,41 @@ public void InsertCheckKey()
}
}
+ public void InsertAndUpdateExplicitKey()
+ {
+ using (var connection = GetOpenConnection())
+ {
+ if (SqlMapperExtensions.GetFormatter(connection) is PostgresAdapter)
+ {
+ //Create the object using a defined primary key (instead of DEFAULT).
+ connection.Get<Houses>(99).IsNull();
+ Houses user = new Houses {Id = 99, Number = 43, Road = "House St"};
+ bool gotException = false;
+ try
+ {
+ connection.Insert(user); //This should fail, as the primary key will be excluded from the query.
+ }
+ catch (NpgsqlException)
+ {
+ gotException = true;
+ }
+ catch (Exception)
+ {
+ }
+ gotException.IsEqualTo(true);
+ int id = (int)connection.Insert(user, useDefaultForKeyValues: false); //No key returned by db due to lack of identity.
+ user.Id.IsEqualTo(id);
+
+ //Update the item.
+ user.Number = 44;
+ connection.Update(user);
+
+ //Ensure that the new item was updated using the primary key.
+ user.Number.IsEqualTo(connection.Query<Houses>("SELECT * FROM houses WHERE Id = :id", new {id = 99}).First().Number);
+ }
+ }
+ }
+
public void BuilderSelectClause()
{
using (var connection = GetOpenConnection())
@@ -148,7 +188,7 @@ public void BuilderSelectClause()
public void BuilderTemplateWOComposition()
{
var builder = new SqlBuilder();
- var template = builder.AddTemplate("SELECT COUNT(*) FROM Users WHERE Age = @age", new {age = 5});
+ var template = builder.AddTemplate("SELECT COUNT(*) AS count FROM Users WHERE Age = @age", new {age = 5});
if (template.RawSql == null) throw new Exception("RawSql null");
if (template.Parameters == null) throw new Exception("Parameters null");
@@ -156,8 +196,8 @@ public void BuilderTemplateWOComposition()
using (var connection = GetOpenConnection())
{
connection.Insert(new User { Age = 5, Name = "Testy McTestington" });
-
- if (connection.Query<int>(template.RawSql, template.Parameters).Single() != 1)
+ var v = connection.Query(template.RawSql, template.Parameters).First();
+ if (Convert.ToInt32(v.count) != 1)
throw new Exception("Query failed");
}
}
View
28 Dapper.Contrib/SqlMapperExtensions.cs
@@ -126,7 +126,9 @@ public static bool IsWriteable(PropertyInfo pi)
foreach (var property in TypePropertiesCache(type))
{
- var val = res[property.Name];
+ object val;
+ if (!res.TryGetValue(property.Name, out val))
+ val = res[property.Name.ToLower()];
property.SetValue(obj, val, null);
}
@@ -163,38 +165,40 @@ private static string GetTableName(Type type)
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToInsert">Entity to insert</param>
+ /// <param name="useDefaultForKeyValues">By default true. If set to false, the key values will be explicitly defined instead of relying on a 'DEFAULT' value.</param>
/// <returns>Identity of inserted entity</returns>
- public static long Insert<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
+ public static long Insert<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null, bool useDefaultForKeyValues = true) where T : class
{
-
+
var type = typeof(T);
var name = GetTableName(type);
var sbColumnList = new StringBuilder(null);
- var allProperties = TypePropertiesCache(type);
+ var properties = TypePropertiesCache(type);
var keyProperties = KeyPropertiesCache(type);
- var allPropertiesExceptKey = allProperties.Except(keyProperties);
+ if (useDefaultForKeyValues)
+ properties = properties.Except(keyProperties);
- for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
+ for (var i = 0; i < properties.Count(); i++)
{
- var property = allPropertiesExceptKey.ElementAt(i);
+ var property = properties.ElementAt(i);
sbColumnList.Append(property.Name);
- if (i < allPropertiesExceptKey.Count() - 1)
+ if (i < properties.Count() - 1)
sbColumnList.Append(", ");
}
var sbParameterList = new StringBuilder(null);
- for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
+ for (var i = 0; i < properties.Count(); i++)
{
- var property = allPropertiesExceptKey.ElementAt(i);
+ var property = properties.ElementAt(i);
sbParameterList.AppendFormat("@{0}", property.Name);
- if (i < allPropertiesExceptKey.Count() - 1)
+ if (i < properties.Count() - 1)
sbParameterList.Append(", ");
}
ISqlAdapter adapter = GetFormatter(connection);
- int id = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), sbParameterList.ToString(), keyProperties, entityToInsert);
+ int id = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), sbParameterList.ToString(), keyProperties, entityToInsert);
return id;
}
Something went wrong with that request. Please try again.