Skip to content

Commit

Permalink
Revert to using scope_identity by default and allow override per mode…
Browse files Browse the repository at this point in the history
…l or at database type if needed
  • Loading branch information
schotime committed Oct 8, 2015
1 parent c78a145 commit d415b11
Show file tree
Hide file tree
Showing 27 changed files with 165 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/NPoco.Tests/Common/BaseDBDecoratedTest.cs
Expand Up @@ -30,7 +30,7 @@ public void SetUp()

case 2: // SQL Local DB
TestDatabase = new SQLLocalDatabase();
Database = new Database(TestDatabase.Connection, new SqlServer2008DatabaseType(), IsolationLevel.ReadUncommitted); // Need read uncommitted for the transaction tests
Database = new Database(TestDatabase.Connection, new SqlServer2008DatabaseType() { UseOutputClause = false }, IsolationLevel.ReadUncommitted); // Need read uncommitted for the transaction tests
break;

case 3: // SQL Server
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco.Tests/Common/BaseDBFuentTest.cs
Expand Up @@ -51,7 +51,7 @@ public void SetUp()
case 2: // SQL Local DB
case 3: // SQL Server
TestDatabase = new SQLLocalDatabase();
Database = dbFactory.Build(new Database(TestDatabase.Connection, new SqlServer2008DatabaseType()));
Database = dbFactory.Build(new Database(TestDatabase.Connection, new SqlServer2008DatabaseType() { UseOutputClause = true }));
break;

case 4: // SQL CE
Expand Down
15 changes: 15 additions & 0 deletions src/NPoco.Tests/Common/GuidFromDb.cs
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NPoco.Tests.Common
{
[TableName("GuidFromDb"), PrimaryKey("Id", AutoIncrement = true, UseOutputClause = true)]
public class GuidFromDb
{
public Guid Id { get; private set; }
public string Name { get; set; }
}
}
8 changes: 8 additions & 0 deletions src/NPoco.Tests/Common/JustPrimaryKey.cs
@@ -0,0 +1,8 @@
namespace NPoco.Tests.Common
{
[TableName("JustPrimaryKey"), PrimaryKey("Id", AutoIncrement = true)]
public class JustPrimaryKey
{
public int Id { get; set; }
}
}
15 changes: 15 additions & 0 deletions src/NPoco.Tests/Common/SQLLocalDatabase.cs
Expand Up @@ -183,6 +183,21 @@ Address nvarchar(200)
";
cmd.ExecuteNonQuery();

cmd.CommandText = @"
CREATE TABLE GuidFromDb(
Id uniqueidentifier PRIMARY KEY DEFAULT newid(),
Name nvarchar(30)
);
";
cmd.ExecuteNonQuery();

cmd.CommandText = @"
CREATE TABLE JustPrimaryKey(
Id int IDENTITY(1, 1) PRIMARY KEY NOT NULL
);
";
cmd.ExecuteNonQuery();

Console.WriteLine("Tables (CreateDB): " + Environment.NewLine);
var dt = conn.GetSchema("Tables");
foreach (DataRow row in dt.Rows)
Expand Down
12 changes: 11 additions & 1 deletion src/NPoco.Tests/Common/UserDecorated.cs
Expand Up @@ -8,8 +8,18 @@ namespace NPoco.Tests.Common
[ExplicitColumns]
public class UserDecorated
{
public UserDecorated()
{

}

public UserDecorated(int userId)
{
UserId = userId;
}

[Column("UserId")]
public int UserId { get; set; }
public int UserId { get; private set; }

[Column("Name")]
public string Name { get; set; }
Expand Down
23 changes: 22 additions & 1 deletion src/NPoco.Tests/DecoratedTests/CRUDTests/InsertTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using NPoco.DatabaseTypes;
using NPoco.Tests.Common;
using NUnit.Framework;

Expand Down Expand Up @@ -113,11 +114,31 @@ public void InsertBatch()
Age = x + 1
});

Database.InsertBatch(users, new BatchOptions() { BatchSize = 22 });
Database.InsertBatch(users, new BatchOptions() {BatchSize = 22});

var result = Database.Query<UserDecorated>().Count();

Assert.AreEqual(65, result);
}

[Test]
public void VerifyGuidGeneratedByDbIsSet()
{
var user = new GuidFromDb();
user.Name = "TestName";
Database.Insert(user);
var verify = Database.Single<GuidFromDb>("select * from guidfromdb");
Assert.AreEqual(user.Id, verify.Id);
Assert.AreEqual(user.Name, verify.Name);
}

[Test]
public void VerifyOnlyAutoGeneratedPrimaryKeyInTableIsSet()
{
var user = new JustPrimaryKey();
Database.Insert(user);
var verify = Database.Single<JustPrimaryKey>("select * from justprimarykey");
Assert.AreEqual(user.Id, verify.Id);
}
}
}
10 changes: 6 additions & 4 deletions src/NPoco.Tests/FluentTests/QueryTests/QueryProviderTests.cs
Expand Up @@ -417,17 +417,18 @@ public void QueryWithIncludeNestedOrderByLimitAndProjectionToProjectUser()
{
var users = Database.Query<User>()
.Include(x => x.House)
.Where(x => x.House != null)
.Where(x => x.House.HouseId > 2)
.OrderBy(x => x.House.HouseId)
.Limit(5)
.ProjectTo(x => new ProjectUser() { NameWithAge = x.Name + x.Age });
.ProjectTo(x => new ProjectUser() { UserId = x.UserId, NameWithAge = x.Name + x.Age });

var inmemory = InMemoryUsers.Where(x => x.House != null).OrderBy(x => x.House.HouseId).ToList();

Assert.AreEqual(5, users.Count);
Assert.AreEqual(4, users.Count);
for (int i = 0; i < users.Count; i++)
{
Assert.AreEqual(inmemory[i].Name + inmemory[i].Age, users[i].NameWithAge);
var inMem = inmemory.First(x => x.UserId == users[i].UserId);
Assert.AreEqual(inMem.Name + inMem.Age, users[i].NameWithAge);
}
}

Expand Down Expand Up @@ -483,6 +484,7 @@ public class ProjectUser
{
public string NameWithAge { get; set; }
public object[] Array { get; set; }
public int UserId { get; set; }
}

public class Usersss
Expand Down
2 changes: 2 additions & 0 deletions src/NPoco.Tests/NPoco.Tests.csproj
Expand Up @@ -72,8 +72,10 @@
<Compile Include="Common\ExtraUserInfoDecorated.cs" />
<Compile Include="Common\ExtraUserInfo.cs" />
<Compile Include="Common\FirebirdDefaultMapper.cs" />
<Compile Include="Common\GuidFromDb.cs" />
<Compile Include="Common\InMemoryDatabase.cs" />
<Compile Include="Common\AdHocUser.cs" />
<Compile Include="Common\JustPrimaryKey.cs" />
<Compile Include="Common\SQLLocalDatabase.cs" />
<Compile Include="Common\TestDatabase.cs" />
<Compile Include="Common\User.cs" />
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/AsyncDatabase.cs
Expand Up @@ -73,7 +73,7 @@ public virtual async Task<object> InsertAsync<T>(string tableName, string primar
}
else
{
id = await _dbType.ExecuteInsertAsync(this, cmd, primaryKeyName, poco, preparedInsert.Rawvalues.ToArray()).ConfigureAwait(false);
id = await _dbType.ExecuteInsertAsync(this, cmd, primaryKeyName, preparedInsert.PocoData.TableInfo.UseOutputClause, poco, preparedInsert.Rawvalues.ToArray()).ConfigureAwait(false);
InsertStatements.AssignPrimaryKey(primaryKeyName, poco, id, preparedInsert);
}

Expand Down
4 changes: 2 additions & 2 deletions src/NPoco/Database.cs
Expand Up @@ -1341,7 +1341,7 @@ public virtual object Insert<T>(string tableName, string primaryKeyName, bool au
{
OpenSharedConnectionInternal();

var preparedInsert = InsertStatements.PrepareInsertSql(this, tableName, primaryKeyName, autoIncrement,poco);
var preparedInsert = InsertStatements.PrepareInsertSql(this, tableName, primaryKeyName, autoIncrement, poco);

using (var cmd = CreateCommand(_sharedConnection, preparedInsert.Sql, preparedInsert.Rawvalues.ToArray()))
{
Expand All @@ -1356,7 +1356,7 @@ public virtual object Insert<T>(string tableName, string primaryKeyName, bool au
}
else
{
id = _dbType.ExecuteInsert(this, cmd, primaryKeyName, poco, preparedInsert.Rawvalues.ToArray());
id = _dbType.ExecuteInsert(this, cmd, primaryKeyName, preparedInsert.PocoData.TableInfo.UseOutputClause, poco, preparedInsert.Rawvalues.ToArray());
InsertStatements.AssignPrimaryKey(primaryKeyName, poco, id, preparedInsert);
}

Expand Down
9 changes: 5 additions & 4 deletions src/NPoco/DatabaseType.cs
Expand Up @@ -201,7 +201,7 @@ public virtual string GetAutoIncrementExpression(TableInfo ti)
/// <param name="primaryKeyName">The primary key of the row being inserted.</param>
/// <returns>An expression describing how to return the new primary key value</returns>
/// <remarks>See the SQLServer database provider for an example of how this method is used.</remarks>
public virtual string GetInsertOutputClause(string primaryKeyName)
public virtual string GetInsertOutputClause(string primaryKeyName, bool useOutputClause)
{
return string.Empty;
}
Expand All @@ -212,16 +212,17 @@ public virtual string GetInsertOutputClause(string primaryKeyName)
/// <param name="db">The calling Database object</param>
/// <param name="cmd">The insert command to be executed</param>
/// <param name="primaryKeyName">The primary key of the table being inserted into</param>
/// <param name="useOutputClause"></param>
/// <param name="poco"></param>
/// <param name="args"></param>
/// <returns>The ID of the newly inserted record</returns>
public virtual object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public virtual object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
cmd.CommandText += ";\nSELECT @@IDENTITY AS NewID;";
return db.ExecuteScalarHelper(cmd);
}
#if NET45
public virtual async System.Threading.Tasks.Task<object> ExecuteInsertAsync<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public virtual async System.Threading.Tasks.Task<object> ExecuteInsertAsync<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
cmd.CommandText += ";\nSELECT @@IDENTITY AS NewID;";
return await db.ExecuteScalarHelperAsync(cmd);
Expand Down Expand Up @@ -285,7 +286,7 @@ public static DatabaseType Resolve(string typeName, string providerName)
return Singleton<SqlServerDatabaseType>.Instance;
}

public virtual string GetDefaultInsertSql(string tableName, string[] names, string[] parameters)
public virtual string GetDefaultInsertSql(string tableName, string primaryKeyName, bool useOutputClause, string[] names, string[] parameters)
{
return string.Format("INSERT INTO {0} DEFAULT VALUES", EscapeTableName(tableName));
}
Expand Down
4 changes: 2 additions & 2 deletions src/NPoco/DatabaseTypes/FirebirdDatabaseType.cs
Expand Up @@ -43,12 +43,12 @@ public override string BuildPageQuery(long skip, long take, PagingHelper.SQLPart
}


public override string GetDefaultInsertSql(string tableName, string[] names, string[] parameters)
public override string GetDefaultInsertSql(string tableName, string primaryKeyName, bool useOutputClause, string[] names, string[] parameters)
{
return string.Format("INSERT INTO {0} ({1}) VALUES ({2})", EscapeTableName(tableName), string.Join(",", names), string.Join(",", parameters));
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
if (primaryKeyName != null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/DatabaseTypes/MySqlDatabaseType.cs
Expand Up @@ -27,7 +27,7 @@ public override string GetExistsSql()
return "SELECT EXISTS (SELECT 1 FROM {0} WHERE {1})";
}

public override string GetDefaultInsertSql(string tableName, string[] names, string[] parameters)
public override string GetDefaultInsertSql(string tableName, string primaryKeyName, bool useOutputClause, string[] names, string[] parameters)
{
return string.Format("INSERT INTO {0} ({1}) VALUES ({2})", EscapeTableName(tableName), string.Join(",", names), string.Join(",", parameters));
}
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/DatabaseTypes/OracleDatabaseType.cs
Expand Up @@ -38,7 +38,7 @@ public override string GetAutoIncrementExpression(TableInfo ti)
return null;
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
if (primaryKeyName != null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/DatabaseTypes/PostgreSQLDatabaseType.cs
Expand Up @@ -17,7 +17,7 @@ public override string EscapeSqlIdentifier(string str)
return string.Format("\"{0}\"", str);
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
if (primaryKeyName != null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs
Expand Up @@ -12,7 +12,7 @@ public override object MapParameterValue(object value)
return base.MapParameterValue(value);
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
if (primaryKeyName != null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/NPoco/DatabaseTypes/SqlServerCEDatabaseType.cs
Expand Up @@ -12,7 +12,7 @@ public override string BuildPageQuery(long skip, long take, PagingHelper.SQLPart
return sqlPage;
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
db.ExecuteNonQueryHelper(cmd);
return db.ExecuteScalar<object>("SELECT @@@IDENTITY AS NewID;");
Expand Down
38 changes: 34 additions & 4 deletions src/NPoco/DatabaseTypes/SqlServerDatabaseType.cs
Expand Up @@ -9,6 +9,8 @@ namespace NPoco.DatabaseTypes
{
public class SqlServerDatabaseType : DatabaseType
{
public bool UseOutputClause { get; set; }

private static readonly Regex OrderByAlias = new Regex(@"[\""\[\]\w]+\.([\[\]\""\w]+)", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);

public override bool UseColumnAliases()
Expand All @@ -26,19 +28,38 @@ public override string BuildPageQuery(long skip, long take, PagingHelper.SQLPart
return sqlPage;
}

public override string GetInsertOutputClause(string primaryKeyName)
private void AdjustSqlInsertCommandText(IDbCommand cmd, bool useOutputClause)
{
return string.Format(" OUTPUT INSERTED.[{0}]", primaryKeyName);
if (!UseOutputClause && !useOutputClause)
{
cmd.CommandText += ";SELECT SCOPE_IDENTITY();";
}
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override string GetInsertOutputClause(string primaryKeyName, bool useOutputClause)
{
if (UseOutputClause || useOutputClause)
{
return string.Format(" OUTPUT INSERTED.{0}", EscapeSqlIdentifier(primaryKeyName));
}
return base.GetInsertOutputClause(primaryKeyName, useOutputClause);
}

public override string GetDefaultInsertSql(string tableName, string primaryKeyName, bool useOutputClause, string[] names, string[] parameters)
{
return string.Format("INSERT INTO {0}{1} DEFAULT VALUES", EscapeTableName(tableName), GetInsertOutputClause(primaryKeyName, useOutputClause));
}

public override object ExecuteInsert<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
AdjustSqlInsertCommandText(cmd, useOutputClause);
return db.ExecuteScalarHelper(cmd);
}

#if NET45
public override System.Threading.Tasks.Task<object> ExecuteInsertAsync<T>(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args)
public override System.Threading.Tasks.Task<object> ExecuteInsertAsync<T>(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args)
{
AdjustSqlInsertCommandText(cmd, useOutputClause);
return ExecuteScalarAsync(db, cmd);
}

Expand All @@ -56,7 +77,16 @@ public override async System.Threading.Tasks.Task<object> ExecuteScalarAsync(Dat

if (dbCommand != null)
{
#if NET40ASYNC
using (var reader = await dbCommand.ExecuteReaderAsync())
{
if (reader.FieldCount > 0 && reader.Read())
return await TaskAsyncHelper.FromResult(reader.GetValue(0));
return TaskAsyncHelper.FromResult((object)null);
}
#else
return await dbCommand.ExecuteScalarAsync().ConfigureAwait(false);
#endif
}
return await base.ExecuteScalarAsync(database, cmd).ConfigureAwait(false);
}
Expand Down
2 changes: 2 additions & 0 deletions src/NPoco/FluentMappings/ConventionScannerSettings.cs
Expand Up @@ -23,6 +23,7 @@ public ConventionScannerSettings()
public Func<Type, string> PrimaryKeysNamed { get; set; }
public Func<Type, bool> PrimaryKeysAutoIncremented { get; set; }
public Func<Type, string> SequencesNamed { get; set; }
public Func<Type, bool> UseOutputClauseWhere { get; set; }

public Func<MemberInfo, string> DbColumnsNamed { get; set; }
public Func<MemberInfo, string> AliasNamed { get; set; }
Expand All @@ -38,6 +39,7 @@ public ConventionScannerSettings()
public Func<MemberInfo, string> ReferenceDbColumnsNamed { get; set; }
public Func<MemberInfo, bool> DbColumnWhere { get; set; }
public Func<MemberInfo, bool> SerializedWhere { get; set; }


public bool Lazy { get; set; }

Expand Down

0 comments on commit d415b11

Please sign in to comment.