Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 8e54495

Browse files
committed
Add support for [AutoId] for auto populating Guid PK's
Populated by SQL Server or PostgreSQL, or OrmLite using Guid.NewGuid() for all other DB's
1 parent 9cb0b9e commit 8e54495

File tree

15 files changed

+225
-22
lines changed

15 files changed

+225
-22
lines changed

src/ServiceStack.OrmLite.Firebird/FirebirdOrmLiteDialectProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public override string ToInsertRowStatement(IDbCommand cmd, object objWithProper
125125

126126
foreach (var fieldDef in modelDef.FieldDefinitionsArray)
127127
{
128-
if (fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && modelDef.HasReturnAttribute))
128+
if (fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && HasInsertReturnValues(modelDef)))
129129
{
130130
if (sbReturningColumns.Length > 0)
131131
sbReturningColumns.Append(",");
@@ -199,7 +199,7 @@ public override void PrepareParameterizedInsertStatement<T>(IDbCommand cmd, ICol
199199

200200
foreach (var fieldDef in modelDef.FieldDefinitionsArray)
201201
{
202-
if (fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && modelDef.HasReturnAttribute))
202+
if (fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && HasInsertReturnValues(modelDef)))
203203
{
204204
if (sbReturningColumns.Length > 0)
205205
sbReturningColumns.Append(",");

src/ServiceStack.OrmLite.PostgreSQL/PostgreSQLDialectProvider.cs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Data;
4+
using System.Linq;
45
using System.Text;
56
using System.Threading;
67
using System.Threading.Tasks;
@@ -17,14 +18,15 @@ public class PostgreSqlDialectProvider : OrmLiteDialectProviderBase<PostgreSqlDi
1718
{
1819
public static PostgreSqlDialectProvider Instance = new PostgreSqlDialectProvider();
1920

20-
public bool UseReturningForLastInsertId { get; set; }
21+
public bool UseReturningForLastInsertId { get; set; } = true;
22+
23+
public string AutoIdGuidFunction { get; set; } = "uuid_generate_v4()";
2124

2225
public PostgreSqlDialectProvider()
2326
{
2427
base.AutoIncrementDefinition = "";
2528
base.ParamString = ":";
2629
base.SelectIdentitySql = "SELECT LASTVAL()";
27-
this.UseReturningForLastInsertId = true;
2830
this.NamingStrategy = new PostgreSqlNamingStrategy();
2931
this.StringSerializer = new JsonStringSerializer();
3032

@@ -221,6 +223,71 @@ public override string GetColumnDefinition(FieldDefinition fieldDef)
221223
return definition;
222224
}
223225

226+
public override string GetAutoIdDefaultValue(FieldDefinition fieldDef)
227+
{
228+
return fieldDef.FieldType == typeof(Guid)
229+
? AutoIdGuidFunction
230+
: null;
231+
}
232+
233+
protected override bool ShouldSkipInsert(FieldDefinition fieldDef) =>
234+
fieldDef.ShouldSkipInsert() || fieldDef.AutoId;
235+
236+
protected virtual bool ShouldReturnOnInsert(ModelDefinition modelDef, FieldDefinition fieldDef) =>
237+
fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && HasInsertReturnValues(modelDef)) || fieldDef.AutoId;
238+
239+
public override bool HasInsertReturnValues(ModelDefinition modelDef) =>
240+
modelDef.FieldDefinitions.Any(x => x.ReturnOnInsert || (x.AutoId && x.FieldType == typeof(Guid)));
241+
242+
public override void PrepareParameterizedInsertStatement<T>(IDbCommand cmd, ICollection<string> insertFields = null)
243+
{
244+
var sbColumnNames = StringBuilderCache.Allocate();
245+
var sbColumnValues = StringBuilderCacheAlt.Allocate();
246+
var sbReturningColumns = StringBuilderCacheAlt.Allocate();
247+
var modelDef = OrmLiteUtils.GetModelDefinition(typeof(T));
248+
249+
cmd.Parameters.Clear();
250+
251+
foreach (var fieldDef in modelDef.FieldDefinitionsArray)
252+
{
253+
if (ShouldReturnOnInsert(modelDef, fieldDef))
254+
{
255+
sbReturningColumns.Append(sbReturningColumns.Length == 0 ? "RETURNING " : ",");
256+
sbReturningColumns.Append(GetQuotedColumnName(fieldDef.FieldName));
257+
}
258+
259+
if (ShouldSkipInsert(fieldDef))
260+
continue;
261+
262+
//insertFields contains Property "Name" of fields to insert ( that's how expressions work )
263+
if (insertFields != null && !insertFields.Contains(fieldDef.Name, StringComparer.OrdinalIgnoreCase))
264+
continue;
265+
266+
if (sbColumnNames.Length > 0)
267+
sbColumnNames.Append(",");
268+
if (sbColumnValues.Length > 0)
269+
sbColumnValues.Append(",");
270+
271+
try
272+
{
273+
sbColumnNames.Append(GetQuotedColumnName(fieldDef.FieldName));
274+
275+
sbColumnValues.Append(this.GetParam(SanitizeFieldNameForParamName(fieldDef.FieldName)));
276+
AddParameter(cmd, fieldDef);
277+
}
278+
catch (Exception ex)
279+
{
280+
Log.Error("ERROR in PrepareParameterizedInsertStatement(): " + ex.Message, ex);
281+
throw;
282+
}
283+
}
284+
285+
var strReturning = StringBuilderCacheAlt.ReturnAndFree(sbReturningColumns);
286+
cmd.CommandText = $"INSERT INTO {GetQuotedTableName(modelDef)} ({StringBuilderCache.ReturnAndFree(sbColumnNames)}) " +
287+
$"VALUES ({StringBuilderCacheAlt.ReturnAndFree(sbColumnValues)})"
288+
+ strReturning;
289+
}
290+
224291
//Convert xmin into an integer so it can be used in comparisons
225292
public const string RowVersionFieldComparer = "int8in(xidout(xmin))";
226293

src/ServiceStack.OrmLite.SqlServer/SqlServerOrmLiteDialectProvider.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ protected virtual string GetAutoIncrementDefinition(FieldDefinition fieldDef)
193193
return AutoIncrementDefinition;
194194
}
195195

196+
public override string GetAutoIdDefaultValue(FieldDefinition fieldDef)
197+
{
198+
return fieldDef.FieldType == typeof(Guid)
199+
? "newid()"
200+
: null;
201+
}
202+
196203
public override string GetColumnDefinition(FieldDefinition fieldDef)
197204
{
198205
// https://msdn.microsoft.com/en-us/library/ms182776.aspx
@@ -310,11 +317,14 @@ protected string Sequence(string schema, string sequence)
310317
+ GetQuotedName(sequence);
311318
}
312319

320+
protected override bool ShouldSkipInsert(FieldDefinition fieldDef) =>
321+
fieldDef.ShouldSkipInsert() || fieldDef.AutoId;
322+
313323
protected virtual bool ShouldReturnOnInsert(ModelDefinition modelDef, FieldDefinition fieldDef) =>
314-
fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && modelDef.HasReturnAttribute);
324+
fieldDef.ReturnOnInsert || (fieldDef.IsPrimaryKey && fieldDef.AutoIncrement && HasInsertReturnValues(modelDef)) || fieldDef.AutoId;
315325

316-
protected virtual bool ShouldSkipInsert(FieldDefinition fieldDef) =>
317-
fieldDef.ShouldSkipInsert();
326+
public override bool HasInsertReturnValues(ModelDefinition modelDef) =>
327+
modelDef.FieldDefinitions.Any(x => x.ReturnOnInsert || (x.AutoId && x.FieldType == typeof(Guid)));
318328

319329
protected virtual bool SupportsSequences(FieldDefinition fieldDef) => false;
320330

src/ServiceStack.OrmLite.SqlServerTests/InsertParam_GetLastInsertId.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void Can_retrieve_ServerGuid()
5454
var obj = new ServerGuid { Name = "foo" };
5555

5656
cmd.GetDialectProvider().PrepareParameterizedInsertStatement<ServerGuid>(cmd,
57-
insertFields: OrmLiteUtils.GetNonDefaultValueInsertFields(obj));
57+
insertFields: db.GetDialectProvider().GetNonDefaultValueInsertFields(obj));
5858

5959
cmd.CommandText = cmd.CommandText.Replace("VALUES", "OUTPUT inserted.Id VALUES");
6060

src/ServiceStack.OrmLite.SqlServerTests/ReturnAttributeTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Data;
1+
using System;
2+
using System.Data;
23
using System.Configuration;
34
using ServiceStack.DataAnnotations;
45
using ServiceStack.OrmLite;
@@ -130,5 +131,6 @@ public void Does_generate_Sql_with_Sequence()
130131
Assert.That(sql, Is.EqualTo("INSERT INTO \"UserSequence\" (\"Id\",\"Name\",\"UserName\",\"Email\") OUTPUT INSERTED.\"Id\" VALUES (NEXT VALUE FOR \"Gen_UserSequence_Id\",@Name,@UserName,@Email)"), "normal Insert");
131132
}
132133
}
134+
133135
}
134136
}

src/ServiceStack.OrmLite.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{6CEB3EDE
88
..\build\build.bat = ..\build\build.bat
99
..\build\build.proj = ..\build\build.proj
1010
..\build\build.tasks = ..\build\build.tasks
11-
..\build\copy.bat = ..\build\copy.bat
1211
..\README.md = ..\README.md
1312
..\NuGet\ServiceStack.OrmLite.Core\servicestack.ormlite.core.nuspec = ..\NuGet\ServiceStack.OrmLite.Core\servicestack.ormlite.core.nuspec
1413
..\NuGet\ServiceStack.OrmLite.Firebird\servicestack.ormlite.firebird.nuspec = ..\NuGet\ServiceStack.OrmLite.Firebird\servicestack.ormlite.firebird.nuspec
@@ -27,6 +26,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{6CEB3EDE
2726
..\NuGet\ServiceStack.OrmLite.SqlServer.Core\servicestack.ormlite.sqlserver.core.nuspec = ..\NuGet\ServiceStack.OrmLite.SqlServer.Core\servicestack.ormlite.sqlserver.core.nuspec
2827
..\NuGet\ServiceStack.OrmLite.SqlServer\servicestack.ormlite.sqlserver.nuspec = ..\NuGet\ServiceStack.OrmLite.SqlServer\servicestack.ormlite.sqlserver.nuspec
2928
..\NuGet\ServiceStack.OrmLite.T4\servicestack.ormlite.t4.nuspec = ..\NuGet\ServiceStack.OrmLite.T4\servicestack.ormlite.t4.nuspec
29+
..\lib\copy.bat = ..\lib\copy.bat
3030
EndProjectSection
3131
EndProject
3232
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceStack.OrmLite.Sqlite", "ServiceStack.OrmLite.Sqlite\ServiceStack.OrmLite.Sqlite.csproj", "{CF68A37D-D071-469D-AE04-68594CB95382}"

src/ServiceStack.OrmLite/Async/OrmLiteWriteCommandExtensionsAsync.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ internal static Task<long> InsertAsync<T>(this IDbCommand dbCmd, T obj, Action<I
269269
var dialectProvider = dbCmd.GetDialectProvider();
270270

271271
dialectProvider.PrepareParameterizedInsertStatement<T>(dbCmd,
272-
insertFields: OrmLiteUtils.GetNonDefaultValueInsertFields(obj));
272+
insertFields: dialectProvider.GetNonDefaultValueInsertFields(obj));
273273

274274
dialectProvider.SetParameterValues<T>(dbCmd, obj);
275275

src/ServiceStack.OrmLite/FieldDefinition.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public class FieldDefinition
3636

3737
public bool AutoIncrement { get; set; }
3838

39+
public bool AutoId { get; set; }
40+
3941
public bool IsNullable { get; set; }
4042

4143
public bool IsIndexed { get; set; }
@@ -138,6 +140,7 @@ public FieldDefinition Clone(Action<FieldDefinition> modifier = null)
138140
PropertyInfo = PropertyInfo,
139141
IsPrimaryKey = IsPrimaryKey,
140142
AutoIncrement = AutoIncrement,
143+
AutoId = AutoId,
141144
IsNullable = IsNullable,
142145
IsIndexed = IsIndexed,
143146
IsUniqueIndex = IsUniqueIndex,

src/ServiceStack.OrmLite/IOrmLiteDialectProvider.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ public interface IOrmLiteDialectProvider
6565

6666
string GetDefaultValue(Type tableType, string fieldName);
6767

68+
string GetDefaultValue(FieldDefinition fieldDef);
69+
70+
bool HasInsertReturnValues(ModelDefinition modelDef);
71+
6872
object GetParamValue(object value, Type fieldType);
6973

7074
object ToDbValue(object value, Type type);
@@ -105,8 +109,10 @@ public interface IOrmLiteDialectProvider
105109

106110
void PrepareParameterizedInsertStatement<T>(IDbCommand cmd, ICollection<string> insertFields = null);
107111

112+
/// <returns>If had RowVersion</returns>
108113
bool PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null);
109114

115+
/// <returns>If had RowVersion</returns>
110116
bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IDictionary<string, object> delteFieldValues);
111117

112118
void PrepareStoredProcedureStatement<T>(IDbCommand cmd, T obj);

src/ServiceStack.OrmLite/ModelDefinition.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ public ModelDefinition()
4747

4848
public bool HasAutoIncrementId => PrimaryKey != null && PrimaryKey.AutoIncrement;
4949

50-
public bool HasReturnAttribute => this.FieldDefinitions.Any(x => x.ReturnOnInsert);
51-
5250
public bool HasSequenceAttribute => this.FieldDefinitions.Any(x => !x.Sequence.IsNullOrEmpty());
5351

5452
public FieldDefinition RowVersion { get; set; }

0 commit comments

Comments
 (0)