From d415b1176df16dc85cfb69313f9031b5fde62de9 Mon Sep 17 00:00:00 2001 From: Adam Schroder Date: Sat, 22 Aug 2015 11:28:26 +1000 Subject: [PATCH] Revert to using scope_identity by default and allow override per model or at database type if needed --- src/NPoco.Tests/Common/BaseDBDecoratedTest.cs | 2 +- src/NPoco.Tests/Common/BaseDBFuentTest.cs | 2 +- src/NPoco.Tests/Common/GuidFromDb.cs | 15 ++++++++ src/NPoco.Tests/Common/JustPrimaryKey.cs | 8 ++++ src/NPoco.Tests/Common/SQLLocalDatabase.cs | 15 ++++++++ src/NPoco.Tests/Common/UserDecorated.cs | 12 +++++- .../DecoratedTests/CRUDTests/InsertTests.cs | 23 ++++++++++- .../QueryTests/QueryProviderTests.cs | 10 +++-- src/NPoco.Tests/NPoco.Tests.csproj | 2 + src/NPoco/AsyncDatabase.cs | 2 +- src/NPoco/Database.cs | 4 +- src/NPoco/DatabaseType.cs | 9 +++-- .../DatabaseTypes/FirebirdDatabaseType.cs | 4 +- src/NPoco/DatabaseTypes/MySqlDatabaseType.cs | 2 +- src/NPoco/DatabaseTypes/OracleDatabaseType.cs | 2 +- .../DatabaseTypes/PostgreSQLDatabaseType.cs | 2 +- src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs | 2 +- .../DatabaseTypes/SqlServerCEDatabaseType.cs | 2 +- .../DatabaseTypes/SqlServerDatabaseType.cs | 38 +++++++++++++++++-- .../ConventionScannerSettings.cs | 2 + .../FluentMappingConfiguration.cs | 4 ++ src/NPoco/FluentMappings/Map.cs | 16 ++++++++ src/NPoco/FluentMappings/TypeDefinition.cs | 1 + src/NPoco/InsertStatements.cs | 7 ++-- src/NPoco/Linq/ComplexSqlBuilder.cs | 7 ++-- src/NPoco/PrimaryKeyAttribute.cs | 1 + src/NPoco/TableInfo.cs | 5 ++- 27 files changed, 165 insertions(+), 34 deletions(-) create mode 100644 src/NPoco.Tests/Common/GuidFromDb.cs create mode 100644 src/NPoco.Tests/Common/JustPrimaryKey.cs diff --git a/src/NPoco.Tests/Common/BaseDBDecoratedTest.cs b/src/NPoco.Tests/Common/BaseDBDecoratedTest.cs index 9bb7dd4b..78392df7 100644 --- a/src/NPoco.Tests/Common/BaseDBDecoratedTest.cs +++ b/src/NPoco.Tests/Common/BaseDBDecoratedTest.cs @@ -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 diff --git a/src/NPoco.Tests/Common/BaseDBFuentTest.cs b/src/NPoco.Tests/Common/BaseDBFuentTest.cs index 98d02277..a99aa329 100644 --- a/src/NPoco.Tests/Common/BaseDBFuentTest.cs +++ b/src/NPoco.Tests/Common/BaseDBFuentTest.cs @@ -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 diff --git a/src/NPoco.Tests/Common/GuidFromDb.cs b/src/NPoco.Tests/Common/GuidFromDb.cs new file mode 100644 index 00000000..47b9d39a --- /dev/null +++ b/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; } + } +} diff --git a/src/NPoco.Tests/Common/JustPrimaryKey.cs b/src/NPoco.Tests/Common/JustPrimaryKey.cs new file mode 100644 index 00000000..de00c118 --- /dev/null +++ b/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; } + } +} \ No newline at end of file diff --git a/src/NPoco.Tests/Common/SQLLocalDatabase.cs b/src/NPoco.Tests/Common/SQLLocalDatabase.cs index 5071cc50..5072b640 100644 --- a/src/NPoco.Tests/Common/SQLLocalDatabase.cs +++ b/src/NPoco.Tests/Common/SQLLocalDatabase.cs @@ -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) diff --git a/src/NPoco.Tests/Common/UserDecorated.cs b/src/NPoco.Tests/Common/UserDecorated.cs index 3f6354fa..ab398d35 100644 --- a/src/NPoco.Tests/Common/UserDecorated.cs +++ b/src/NPoco.Tests/Common/UserDecorated.cs @@ -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; } diff --git a/src/NPoco.Tests/DecoratedTests/CRUDTests/InsertTests.cs b/src/NPoco.Tests/DecoratedTests/CRUDTests/InsertTests.cs index 364d6f0e..cbf286d5 100644 --- a/src/NPoco.Tests/DecoratedTests/CRUDTests/InsertTests.cs +++ b/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; @@ -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().Count(); Assert.AreEqual(65, result); } + + [Test] + public void VerifyGuidGeneratedByDbIsSet() + { + var user = new GuidFromDb(); + user.Name = "TestName"; + Database.Insert(user); + var verify = Database.Single("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("select * from justprimarykey"); + Assert.AreEqual(user.Id, verify.Id); + } } } \ No newline at end of file diff --git a/src/NPoco.Tests/FluentTests/QueryTests/QueryProviderTests.cs b/src/NPoco.Tests/FluentTests/QueryTests/QueryProviderTests.cs index 7eed3cf5..2a03baed 100644 --- a/src/NPoco.Tests/FluentTests/QueryTests/QueryProviderTests.cs +++ b/src/NPoco.Tests/FluentTests/QueryTests/QueryProviderTests.cs @@ -417,17 +417,18 @@ public void QueryWithIncludeNestedOrderByLimitAndProjectionToProjectUser() { var users = Database.Query() .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); } } @@ -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 diff --git a/src/NPoco.Tests/NPoco.Tests.csproj b/src/NPoco.Tests/NPoco.Tests.csproj index a796d9e7..9fa43f49 100644 --- a/src/NPoco.Tests/NPoco.Tests.csproj +++ b/src/NPoco.Tests/NPoco.Tests.csproj @@ -72,8 +72,10 @@ + + diff --git a/src/NPoco/AsyncDatabase.cs b/src/NPoco/AsyncDatabase.cs index c9907a19..0be1c6a9 100644 --- a/src/NPoco/AsyncDatabase.cs +++ b/src/NPoco/AsyncDatabase.cs @@ -73,7 +73,7 @@ public virtual async Task InsertAsync(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); } diff --git a/src/NPoco/Database.cs b/src/NPoco/Database.cs index 12be42bf..59096006 100644 --- a/src/NPoco/Database.cs +++ b/src/NPoco/Database.cs @@ -1341,7 +1341,7 @@ public virtual object Insert(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())) { @@ -1356,7 +1356,7 @@ public virtual object Insert(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); } diff --git a/src/NPoco/DatabaseType.cs b/src/NPoco/DatabaseType.cs index 7371312b..fdb78526 100644 --- a/src/NPoco/DatabaseType.cs +++ b/src/NPoco/DatabaseType.cs @@ -201,7 +201,7 @@ public virtual string GetAutoIncrementExpression(TableInfo ti) /// The primary key of the row being inserted. /// An expression describing how to return the new primary key value /// See the SQLServer database provider for an example of how this method is used. - public virtual string GetInsertOutputClause(string primaryKeyName) + public virtual string GetInsertOutputClause(string primaryKeyName, bool useOutputClause) { return string.Empty; } @@ -212,16 +212,17 @@ public virtual string GetInsertOutputClause(string primaryKeyName) /// The calling Database object /// The insert command to be executed /// The primary key of the table being inserted into + /// /// /// /// The ID of the newly inserted record - public virtual object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public virtual object ExecuteInsert(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 ExecuteInsertAsync(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public virtual async System.Threading.Tasks.Task ExecuteInsertAsync(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { cmd.CommandText += ";\nSELECT @@IDENTITY AS NewID;"; return await db.ExecuteScalarHelperAsync(cmd); @@ -285,7 +286,7 @@ public static DatabaseType Resolve(string typeName, string providerName) return Singleton.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)); } diff --git a/src/NPoco/DatabaseTypes/FirebirdDatabaseType.cs b/src/NPoco/DatabaseTypes/FirebirdDatabaseType.cs index 93c7a009..08548916 100644 --- a/src/NPoco/DatabaseTypes/FirebirdDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/FirebirdDatabaseType.cs @@ -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(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { if (primaryKeyName != null) { diff --git a/src/NPoco/DatabaseTypes/MySqlDatabaseType.cs b/src/NPoco/DatabaseTypes/MySqlDatabaseType.cs index 2f13c2f9..8157519c 100644 --- a/src/NPoco/DatabaseTypes/MySqlDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/MySqlDatabaseType.cs @@ -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)); } diff --git a/src/NPoco/DatabaseTypes/OracleDatabaseType.cs b/src/NPoco/DatabaseTypes/OracleDatabaseType.cs index 7f1ba00f..556629b1 100644 --- a/src/NPoco/DatabaseTypes/OracleDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/OracleDatabaseType.cs @@ -38,7 +38,7 @@ public override string GetAutoIncrementExpression(TableInfo ti) return null; } - public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { if (primaryKeyName != null) { diff --git a/src/NPoco/DatabaseTypes/PostgreSQLDatabaseType.cs b/src/NPoco/DatabaseTypes/PostgreSQLDatabaseType.cs index 0a1043c0..e5c8beaa 100644 --- a/src/NPoco/DatabaseTypes/PostgreSQLDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/PostgreSQLDatabaseType.cs @@ -17,7 +17,7 @@ public override string EscapeSqlIdentifier(string str) return string.Format("\"{0}\"", str); } - public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { if (primaryKeyName != null) { diff --git a/src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs b/src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs index aa8acf8f..e386a007 100644 --- a/src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/SQLiteDatabaseType.cs @@ -12,7 +12,7 @@ public override object MapParameterValue(object value) return base.MapParameterValue(value); } - public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { if (primaryKeyName != null) { diff --git a/src/NPoco/DatabaseTypes/SqlServerCEDatabaseType.cs b/src/NPoco/DatabaseTypes/SqlServerCEDatabaseType.cs index 754bf5a2..889e142b 100644 --- a/src/NPoco/DatabaseTypes/SqlServerCEDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/SqlServerCEDatabaseType.cs @@ -12,7 +12,7 @@ public override string BuildPageQuery(long skip, long take, PagingHelper.SQLPart return sqlPage; } - public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { db.ExecuteNonQueryHelper(cmd); return db.ExecuteScalar("SELECT @@@IDENTITY AS NewID;"); diff --git a/src/NPoco/DatabaseTypes/SqlServerDatabaseType.cs b/src/NPoco/DatabaseTypes/SqlServerDatabaseType.cs index 44e48bfa..66e8c886 100644 --- a/src/NPoco/DatabaseTypes/SqlServerDatabaseType.cs +++ b/src/NPoco/DatabaseTypes/SqlServerDatabaseType.cs @@ -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() @@ -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(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(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 ExecuteInsertAsync(Database db, IDbCommand cmd, string primaryKeyName, T poco, object[] args) + public override System.Threading.Tasks.Task ExecuteInsertAsync(Database db, IDbCommand cmd, string primaryKeyName, bool useOutputClause, T poco, object[] args) { + AdjustSqlInsertCommandText(cmd, useOutputClause); return ExecuteScalarAsync(db, cmd); } @@ -56,7 +77,16 @@ public override async System.Threading.Tasks.Task 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); } diff --git a/src/NPoco/FluentMappings/ConventionScannerSettings.cs b/src/NPoco/FluentMappings/ConventionScannerSettings.cs index 72381f1d..4b627a8a 100644 --- a/src/NPoco/FluentMappings/ConventionScannerSettings.cs +++ b/src/NPoco/FluentMappings/ConventionScannerSettings.cs @@ -23,6 +23,7 @@ public ConventionScannerSettings() public Func PrimaryKeysNamed { get; set; } public Func PrimaryKeysAutoIncremented { get; set; } public Func SequencesNamed { get; set; } + public Func UseOutputClauseWhere { get; set; } public Func DbColumnsNamed { get; set; } public Func AliasNamed { get; set; } @@ -38,6 +39,7 @@ public ConventionScannerSettings() public Func ReferenceDbColumnsNamed { get; set; } public Func DbColumnWhere { get; set; } public Func SerializedWhere { get; set; } + public bool Lazy { get; set; } diff --git a/src/NPoco/FluentMappings/FluentMappingConfiguration.cs b/src/NPoco/FluentMappings/FluentMappingConfiguration.cs index 22835fac..d3e13fe4 100644 --- a/src/NPoco/FluentMappings/FluentMappingConfiguration.cs +++ b/src/NPoco/FluentMappings/FluentMappingConfiguration.cs @@ -56,6 +56,7 @@ private static Mappings CreateMappings(ConventionScannerSettings scannerSettings PrimaryKey = scannerSettings.PrimaryKeysNamed(type), TableName = scannerSettings.TablesNamed(type), SequenceName = scannerSettings.SequencesNamed(type), + UseOutputClause = scannerSettings.UseOutputClauseWhere(type), ExplicitColumns = true }; @@ -162,6 +163,7 @@ private static ConventionScannerSettings ProcessSettings(Action x.GetMemberInfoType().IsAClass() && Attribute.GetCustomAttributes(x, typeof(ComplexMappingAttribute)).Any(), ReferenceDbColumnsNamed = x => x.Name + "ID", SequencesNamed = x => null, + UseOutputClauseWhere = x => false, SerializedWhere = x => Attribute.GetCustomAttributes(x, typeof(SerializedColumnAttribute)).Any(), DbColumnWhere = x => Attribute.GetCustomAttributes(x, typeof(ColumnAttribute)).Any(), Lazy = false @@ -191,6 +193,7 @@ private static void MergeAttributeOverrides(Dictionary con typeDefinition.Value.PrimaryKey = tableInfo.PrimaryKey; typeDefinition.Value.SequenceName = tableInfo.SequenceName; typeDefinition.Value.AutoIncrement = tableInfo.AutoIncrement; + typeDefinition.Value.UseOutputClause = tableInfo.UseOutputClause; foreach (var columnDefinition in typeDefinition.Value.ColumnConfiguration) { @@ -226,6 +229,7 @@ private static void MergeOverrides(Dictionary config, Mapp convTableDefinition.TableName = overrideTypeDefinition.Value.TableName ?? convTableDefinition.TableName; convTableDefinition.AutoIncrement = overrideTypeDefinition.Value.AutoIncrement ?? convTableDefinition.AutoIncrement; convTableDefinition.ExplicitColumns = overrideTypeDefinition.Value.ExplicitColumns ?? convTableDefinition.ExplicitColumns; + convTableDefinition.UseOutputClause = overrideTypeDefinition.Value.UseOutputClause ?? convTableDefinition.UseOutputClause; foreach (var overrideColumnDefinition in overrideMappings.Config[overrideTypeDefinition.Key].ColumnConfiguration) { diff --git a/src/NPoco/FluentMappings/Map.cs b/src/NPoco/FluentMappings/Map.cs index ebd18275..ec8fb4e7 100644 --- a/src/NPoco/FluentMappings/Map.cs +++ b/src/NPoco/FluentMappings/Map.cs @@ -85,6 +85,14 @@ public Map PrimaryKey(string primaryKeyColumn, bool autoIncrement) return this; } + public Map PrimaryKey(string primaryKeyColumn, bool autoIncrement, bool useOutputClause) + { + _petaPocoTypeDefinition.PrimaryKey = primaryKeyColumn; + _petaPocoTypeDefinition.AutoIncrement = autoIncrement; + _petaPocoTypeDefinition.UseOutputClause = useOutputClause; + return this; + } + public Map PrimaryKey(string primaryKeyColumn, string sequenceName) { _petaPocoTypeDefinition.PrimaryKey = primaryKeyColumn; @@ -92,6 +100,14 @@ public Map PrimaryKey(string primaryKeyColumn, string sequenceName) return this; } + public Map PrimaryKey(string primaryKeyColumn, string sequenceName, bool useOutputClause) + { + _petaPocoTypeDefinition.PrimaryKey = primaryKeyColumn; + _petaPocoTypeDefinition.SequenceName = sequenceName; + _petaPocoTypeDefinition.UseOutputClause = useOutputClause; + return this; + } + public Map PrimaryKey(string primaryKeyColumn) { return PrimaryKey(primaryKeyColumn, null); diff --git a/src/NPoco/FluentMappings/TypeDefinition.cs b/src/NPoco/FluentMappings/TypeDefinition.cs index c90ff965..5dd86adb 100644 --- a/src/NPoco/FluentMappings/TypeDefinition.cs +++ b/src/NPoco/FluentMappings/TypeDefinition.cs @@ -18,5 +18,6 @@ public TypeDefinition(Type type) public bool? AutoIncrement { get; set; } public bool? ExplicitColumns { get; set; } public Dictionary ColumnConfiguration { get; set; } + public bool? UseOutputClause { get; set; } } } \ No newline at end of file diff --git a/src/NPoco/InsertStatements.cs b/src/NPoco/InsertStatements.cs index a1d46555..2c87d30f 100644 --- a/src/NPoco/InsertStatements.cs +++ b/src/NPoco/InsertStatements.cs @@ -75,9 +75,9 @@ public static PreparedInsertSql PrepareInsertSql(Database database, string ta var sql = string.Empty; var outputClause = String.Empty; - if (autoIncrement) + if (autoIncrement || !string.IsNullOrEmpty(pd.TableInfo.SequenceName)) { - outputClause = database.DatabaseType.GetInsertOutputClause(primaryKeyName); + outputClause = database.DatabaseType.GetInsertOutputClause(primaryKeyName, pd.TableInfo.UseOutputClause); } if (names.Count != 0) @@ -90,8 +90,9 @@ public static PreparedInsertSql PrepareInsertSql(Database database, string ta } else { - sql = database.DatabaseType.GetDefaultInsertSql(tableName, names.ToArray(), values.ToArray()); + sql = database.DatabaseType.GetDefaultInsertSql(tableName, primaryKeyName, pd.TableInfo.UseOutputClause, names.ToArray(), values.ToArray()); } + return new PreparedInsertSql() { PocoData = pd, diff --git a/src/NPoco/Linq/ComplexSqlBuilder.cs b/src/NPoco/Linq/ComplexSqlBuilder.cs index 2783e68c..58dd4427 100644 --- a/src/NPoco/Linq/ComplexSqlBuilder.cs +++ b/src/NPoco/Linq/ComplexSqlBuilder.cs @@ -59,9 +59,8 @@ public Sql BuildJoin(IDatabase database, SqlExpression sqlExpression, List sqlExpression, Listx.StringCol).ToArray()), database.DatabaseType.EscapeTableName(modelDef.TableInfo.TableName) + " " + database.DatabaseType.EscapeTableName(modelDef.TableInfo.AutoAlias), joins, - wheres.SQL, + where, orderbys); var newsql = ((ISqlExpression)_sqlExpression).ApplyPaging(resultantSql, cols.Select(x=>x.PocoColumn), _joinSqlExpressions); - return new Sql(newsql, wheres.Arguments); + return new Sql(newsql, _sqlExpression.Context.Params); } private static string BuildJoinSql(IDatabase database, List joinSqlExpressions, ref List cols) diff --git a/src/NPoco/PrimaryKeyAttribute.cs b/src/NPoco/PrimaryKeyAttribute.cs index 3d13faf7..ef016195 100644 --- a/src/NPoco/PrimaryKeyAttribute.cs +++ b/src/NPoco/PrimaryKeyAttribute.cs @@ -14,5 +14,6 @@ public PrimaryKeyAttribute(string primaryKey) public string Value { get; private set; } public string SequenceName { get; set; } public bool AutoIncrement { get; set; } + public bool UseOutputClause { get; set; } } } \ No newline at end of file diff --git a/src/NPoco/TableInfo.cs b/src/NPoco/TableInfo.cs index 7b2ddd02..f382748e 100644 --- a/src/NPoco/TableInfo.cs +++ b/src/NPoco/TableInfo.cs @@ -10,6 +10,7 @@ public class TableInfo public bool AutoIncrement { get; set; } public string SequenceName { get; set; } public string AutoAlias { get; set; } + public bool UseOutputClause { get; set; } public TableInfo Clone() { @@ -19,7 +20,8 @@ public TableInfo Clone() AutoIncrement = AutoIncrement, TableName = TableName, PrimaryKey = PrimaryKey, - SequenceName = SequenceName + SequenceName = SequenceName, + UseOutputClause = UseOutputClause }; } @@ -36,6 +38,7 @@ public static TableInfo FromPoco(Type t) tableInfo.PrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKeyAttribute).Value; tableInfo.SequenceName = a.Length == 0 ? null : (a[0] as PrimaryKeyAttribute).SequenceName; tableInfo.AutoIncrement = a.Length == 0 ? true : (a[0] as PrimaryKeyAttribute).AutoIncrement; + tableInfo.UseOutputClause = a.Length == 0 ? true : (a[0] as PrimaryKeyAttribute).UseOutputClause; // Set autoincrement false if primary key has multiple columns tableInfo.AutoIncrement = tableInfo.AutoIncrement ? !tableInfo.PrimaryKey.Contains(',') : tableInfo.AutoIncrement;