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

Commit 24a5a14

Browse files
committed
Refactor existing RowVersion support
1 parent 71339f5 commit 24a5a14

File tree

10 files changed

+144
-84
lines changed

10 files changed

+144
-84
lines changed

src/ServiceStack.OrmLite.Sqlite/SqliteOrmLiteDialectProviderBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public override string ToPostCreateTableStatement(ModelDefinition modelDef)
5757
modelDef.RowVersion.FieldName.SqlColumn(),
5858
modelDef.PrimaryKey.FieldName.SqlColumn());
5959

60-
var sql = "CREATE TRIGGER {0} AFTER UPDATE ON {1} FOR EACH ROW BEGIN {2} END;".Fmt(
60+
var sql = "CREATE TRIGGER {0} BEFORE UPDATE ON {1} FOR EACH ROW BEGIN {2} END;".Fmt(
6161
triggerName, modelDef.ModelName, triggerBody);
6262

6363
return sql;
@@ -244,6 +244,9 @@ public override string GetColumnDefinition(string fieldName, Type fieldType, boo
244244
var ret = base.GetColumnDefinition(fieldName, fieldType, isPrimaryKey, autoIncrement, isNullable, isRowVersion, fieldLength, scale, defaultValue, customFieldDefinition);
245245
if (isPrimaryKey)
246246
return ret.Replace(" BIGINT ", " INTEGER ");
247+
if (isRowVersion)
248+
return ret + " DEFAULT 1";
249+
247250
return ret;
248251
}
249252
}

src/ServiceStack.OrmLite/IOrmLiteDialectProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ string GetColumnDefinition(
7878

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

81-
void PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null);
81+
bool PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null);
8282

8383
void PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, ICollection<string> deleteFields = null);
8484

src/ServiceStack.OrmLite/ModelDefinition.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public ModelDefinition()
2626
this.CompositeIndexes = new List<CompositeIndexAttribute>();
2727
}
2828

29+
public const string RowVersionName = "RowVersion";
30+
2931
public string Name { get; set; }
3032

3133
public string Alias { get; set; }

src/ServiceStack.OrmLite/OrmLiteConfigExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ internal static ModelDefinition GetModelDefinition(this Type modelType)
105105
var isPrimaryKey = (!hasPkAttr && (propertyInfo.Name == OrmLiteConfig.IdField || (!hasIdField && isFirst)))
106106
|| propertyInfo.HasAttributeNamed(typeof(PrimaryKeyAttribute).Name);
107107

108-
var isRowVersion = propertyInfo.Name == "RowVersion"
108+
var isRowVersion = propertyInfo.Name == ModelDefinition.RowVersionName
109109
&& propertyInfo.PropertyType == typeof(ulong);
110110

111111
var isNullableType = IsNullableType(propertyInfo.PropertyType);

src/ServiceStack.OrmLite/OrmLiteDialectProviderBase.cs

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ public virtual string ToSelectStatement(Type tableType, string sqlFilter, params
454454
return sqlFilter.SqlFmt(filterParams);
455455

456456
var modelDef = tableType.GetModelDefinition();
457-
var sql = new StringBuilder("SELECT " + tableType.GetColumnNames() + " FROM " + GetQuotedTableName(modelDef));
457+
var sql = new StringBuilder("SELECT " + GetColumnNames(modelDef) + " FROM " + GetQuotedTableName(modelDef));
458458

459459
if (!string.IsNullOrEmpty(sqlFilter))
460460
{
@@ -471,6 +471,20 @@ public virtual string ToSelectStatement(Type tableType, string sqlFilter, params
471471
return sql.ToString();
472472
}
473473

474+
public virtual string GetColumnNames(ModelDefinition modelDef)
475+
{
476+
var sqlColumns = new StringBuilder();
477+
foreach (var field in modelDef.FieldDefinitions)
478+
{
479+
if (sqlColumns.Length > 0)
480+
sqlColumns.Append(", ");
481+
482+
sqlColumns.Append(GetQuotedColumnName(field.FieldName));
483+
}
484+
485+
return sqlColumns.ToString();
486+
}
487+
474488
/// Fmt
475489
public virtual string ToInsertRowStatement(IDbCommand command, object objWithProperties, ICollection<string> insertFields = null)
476490
{
@@ -483,10 +497,12 @@ public virtual string ToInsertRowStatement(IDbCommand command, object objWithPro
483497

484498
foreach (var fieldDef in modelDef.FieldDefinitions)
485499
{
486-
if (fieldDef.IsComputed) continue;
487-
if (fieldDef.AutoIncrement) continue;
500+
if (fieldDef.AutoIncrement || fieldDef.IsComputed || fieldDef.IsRowVersion)
501+
continue;
502+
488503
//insertFields contains Property "Name" of fields to insert ( that's how expressions work )
489-
if (insertFields.Count > 0 && !insertFields.Contains(fieldDef.Name)) continue;
504+
if (insertFields.Count > 0 && !insertFields.Contains(fieldDef.Name))
505+
continue;
490506

491507
if (sbColumnNames.Length > 0) sbColumnNames.Append(",");
492508
if (sbColumnValues.Length > 0) sbColumnValues.Append(",");
@@ -520,10 +536,12 @@ public virtual void PrepareParameterizedInsertStatement<T>(IDbCommand cmd, IColl
520536

521537
foreach (var fieldDef in modelDef.FieldDefinitionsArray)
522538
{
523-
if (fieldDef.AutoIncrement || fieldDef.IsComputed) continue;
539+
if (fieldDef.AutoIncrement || fieldDef.IsComputed || fieldDef.IsRowVersion)
540+
continue;
524541

525542
//insertFields contains Property "Name" of fields to insert ( that's how expressions work )
526-
if (insertFields != null && !insertFields.Contains(fieldDef.Name)) continue;
543+
if (insertFields != null && !insertFields.Contains(fieldDef.Name))
544+
continue;
527545

528546
if (sbColumnNames.Length > 0)
529547
sbColumnNames.Append(",");
@@ -548,63 +566,82 @@ public virtual void PrepareParameterizedInsertStatement<T>(IDbCommand cmd, IColl
548566
GetQuotedTableName(modelDef), sbColumnNames, sbColumnValues);
549567
}
550568

551-
public virtual void PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null)
569+
public virtual bool PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null)
552570
{
553571
var sqlFilter = new StringBuilder();
554572
var sql = new StringBuilder();
555573
var modelDef = typeof(T).GetModelDefinition();
574+
var hadRowVesion = false;
575+
var updateAllFields = updateFields == null || updateFields.Count == 0;
556576

557577
cmd.Parameters.Clear();
558578
cmd.CommandTimeout = OrmLiteConfig.CommandTimeout;
559579

560580
foreach (var fieldDef in modelDef.FieldDefinitions)
561581
{
562-
if (fieldDef.IsComputed) continue;
582+
if (fieldDef.IsComputed)
583+
continue;
584+
563585
try
564586
{
565-
if (fieldDef.IsPrimaryKey && (updateFields == null || updateFields.Count == 0))
587+
if ((fieldDef.IsPrimaryKey || fieldDef.IsRowVersion) && updateAllFields)
566588
{
567-
if (sqlFilter.Length > 0) sqlFilter.Append(" AND ");
589+
if (sqlFilter.Length > 0)
590+
sqlFilter.Append(" AND ");
568591

569-
sqlFilter
570-
.Append(GetQuotedColumnName(fieldDef.FieldName))
571-
.Append("=")
572-
.Append(this.GetParam(SanitizeFieldNameForParamName(fieldDef.FieldName)));
592+
AppendFieldCondition(sqlFilter, fieldDef, cmd);
573593

574-
AddParameter(cmd, fieldDef);
594+
if (fieldDef.IsRowVersion)
595+
hadRowVesion = true;
575596

576597
continue;
577598
}
578599

579-
if ((updateFields != null && updateFields.Count > 0) && !updateFields.Contains(fieldDef.Name))
600+
if (!updateAllFields && !updateFields.Contains(fieldDef.Name))
580601
continue;
581602

582603
if (sql.Length > 0)
583604
sql.Append(", ");
584605

585-
sql.Append(GetQuotedColumnName(fieldDef.FieldName))
586-
.Append("=")
587-
.Append(this.GetParam(SanitizeFieldNameForParamName(fieldDef.FieldName)));
588-
589-
AddParameter(cmd, fieldDef);
606+
AppendFieldCondition(sql, fieldDef, cmd);
590607
}
591608
catch (Exception ex)
592609
{
593610
Log.Error("ERROR in PrepareParameterizedUpdateStatement(): " + ex.Message, ex);
594611
}
595612
}
596613

597-
if (sql.Length < 1)
598-
return;
614+
if (sql.Length > 0)
615+
{
616+
cmd.CommandText = string.Format("UPDATE {0} SET {1} {2}",
617+
GetQuotedTableName(modelDef), sql, (sqlFilter.Length > 0 ? "WHERE " + sqlFilter : ""));
618+
}
619+
620+
return hadRowVesion;
621+
}
622+
623+
public virtual void AppendFieldCondition(StringBuilder sqlFilter, FieldDefinition fieldDef, IDbCommand cmd)
624+
{
625+
sqlFilter
626+
.Append(GetQuotedColumnName(fieldDef.FieldName))
627+
.Append("=")
628+
.Append(this.GetParam(SanitizeFieldNameForParamName(fieldDef.FieldName)));
629+
630+
AddParameter(cmd, fieldDef);
631+
}
599632

600-
cmd.CommandText = string.Format("UPDATE {0} SET {1} {2}",
601-
GetQuotedTableName(modelDef), sql, (sqlFilter.Length > 0 ? "WHERE " + sqlFilter : ""));
633+
public virtual void AppendFieldConditionFmt(StringBuilder sqlFilter, FieldDefinition fieldDef, object objWithProperties)
634+
{
635+
sqlFilter.AppendFormat("{0}={1}",
636+
GetQuotedColumnName(fieldDef.FieldName),
637+
fieldDef.GetQuotedValue(objWithProperties));
602638
}
603639

604640
public virtual void PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, ICollection<string> deleteFields = null)
605641
{
606642
var sqlFilter = new StringBuilder();
607643
var modelDef = typeof(T).GetModelDefinition();
644+
var hasSpecificFilter = deleteFields != null && deleteFields.Count > 0;
608645

609646
cmd.Parameters.Clear();
610647
cmd.CommandTimeout = OrmLiteConfig.CommandTimeout;
@@ -613,20 +650,15 @@ public virtual void PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IColl
613650
{
614651
if (fieldDef.IsComputed) continue;
615652

616-
if ((deleteFields != null && deleteFields.Count > 0) && !deleteFields.Contains(fieldDef.Name))
653+
if (hasSpecificFilter && !deleteFields.Contains(fieldDef.Name))
617654
continue;
618655

619656
try
620657
{
621658
if (sqlFilter.Length > 0)
622659
sqlFilter.Append(" AND ");
623660

624-
sqlFilter
625-
.Append(GetQuotedColumnName(fieldDef.FieldName))
626-
.Append("=")
627-
.Append(this.GetParam(SanitizeFieldNameForParamName(fieldDef.FieldName)));
628-
629-
AddParameter(cmd, fieldDef);
661+
AppendFieldCondition(sqlFilter, fieldDef, cmd);
630662
}
631663
catch (Exception ex)
632664
{
@@ -757,33 +789,32 @@ protected virtual object GetAnonValue<T>(FieldDefinition fieldDef, object obj)
757789

758790
public virtual string ToUpdateRowStatement(object objWithProperties, ICollection<string> updateFields = null)
759791
{
760-
if (updateFields == null)
761-
updateFields = new List<string>();
762-
763792
var sqlFilter = new StringBuilder();
764793
var sql = new StringBuilder();
765794
var modelDef = objWithProperties.GetType().GetModelDefinition();
795+
var updateAllFields = updateFields == null || updateFields.Count == 0;
766796

767797
foreach (var fieldDef in modelDef.FieldDefinitions)
768798
{
769799
if (fieldDef.IsComputed) continue;
770800

771801
try
772802
{
773-
if (fieldDef.IsPrimaryKey && updateFields.Count == 0)
803+
if (fieldDef.IsPrimaryKey && updateAllFields)
774804
{
775-
if (sqlFilter.Length > 0) sqlFilter.Append(" AND ");
805+
if (sqlFilter.Length > 0)
806+
sqlFilter.Append(" AND ");
776807

777-
sqlFilter.AppendFormat("{0}={1}", GetQuotedColumnName(fieldDef.FieldName), fieldDef.GetQuotedValue(objWithProperties));
808+
AppendFieldConditionFmt(sqlFilter, fieldDef, objWithProperties);
778809

779810
continue;
780811
}
781812

782-
if (updateFields.Count > 0 && !updateFields.Contains(fieldDef.Name) || fieldDef.AutoIncrement) continue;
813+
if (!updateAllFields && !updateFields.Contains(fieldDef.Name) || fieldDef.AutoIncrement) continue;
783814
if (sql.Length > 0)
784815
sql.Append(", ");
785816

786-
sql.AppendFormat("{0}={1}", GetQuotedColumnName(fieldDef.FieldName), fieldDef.GetQuotedValue(objWithProperties));
817+
AppendFieldConditionFmt(sql, fieldDef, objWithProperties);
787818
}
788819
catch (Exception ex)
789820
{
@@ -811,9 +842,10 @@ public virtual string ToDeleteRowStatement(object objWithProperties)
811842
{
812843
if (fieldDef.IsPrimaryKey)
813844
{
814-
if (sqlFilter.Length > 0) sqlFilter.Append(" AND ");
845+
if (sqlFilter.Length > 0)
846+
sqlFilter.Append(" AND ");
815847

816-
sqlFilter.AppendFormat("{0} = {1}", GetQuotedColumnName(fieldDef.FieldName), fieldDef.GetQuotedValue(objWithProperties));
848+
AppendFieldConditionFmt(sqlFilter, fieldDef, objWithProperties);
817849
}
818850
}
819851
catch (Exception ex)
@@ -838,7 +870,8 @@ public virtual string ToDeleteStatement(Type tableType, string sqlFilter, params
838870
&& sqlFilter.Length > deleteStatement.Length
839871
&& sqlFilter.Substring(0, deleteStatement.Length).ToUpper().Equals(deleteStatement);
840872

841-
if (isFullDeleteStatement) return sqlFilter.SqlFmt(filterParams);
873+
if (isFullDeleteStatement)
874+
return sqlFilter.SqlFmt(filterParams);
842875

843876
var modelDef = tableType.GetModelDefinition();
844877
sql.AppendFormat("DELETE FROM {0}", GetQuotedTableName(modelDef));
@@ -860,8 +893,6 @@ public virtual string ToCreateTableStatement(Type tableType)
860893
var modelDef = tableType.GetModelDefinition();
861894
foreach (var fieldDef in modelDef.FieldDefinitions)
862895
{
863-
if (sbColumns.Length != 0) sbColumns.Append(", \n ");
864-
865896
var columnDefinition = GetColumnDefinition(
866897
fieldDef.FieldName,
867898
fieldDef.ColumnType,
@@ -874,6 +905,12 @@ public virtual string ToCreateTableStatement(Type tableType)
874905
fieldDef.DefaultValue,
875906
fieldDef.CustomFieldDefinition);
876907

908+
if (columnDefinition == null)
909+
continue;
910+
911+
if (sbColumns.Length != 0)
912+
sbColumns.Append(", \n ");
913+
877914
sbColumns.Append(columnDefinition);
878915

879916
if (fieldDef.ForeignKey == null) continue;
@@ -1005,11 +1042,6 @@ protected virtual string ToCreateIndexStatement(bool isUnique, string indexName,
10051042
(isCombined) ? fieldName : GetQuotedColumnName(fieldName));
10061043
}
10071044

1008-
public virtual string GetColumnNames(ModelDefinition modelDef)
1009-
{
1010-
return modelDef.GetColumnNames();
1011-
}
1012-
10131045
public virtual List<string> ToCreateSequenceStatements(Type tableType)
10141046
{
10151047
return new List<string>();

src/ServiceStack.OrmLite/OrmLiteUtilExtensions.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,12 @@ public static IList ConvertToList(this IDataReader dataReader, Type type)
100100

101101
internal static string GetColumnNames(this Type tableType)
102102
{
103-
var modelDefinition = tableType.GetModelDefinition();
104-
return GetColumnNames(modelDefinition);
103+
return GetColumnNames(tableType.GetModelDefinition());
105104
}
106105

107106
public static string GetColumnNames(this ModelDefinition modelDef)
108107
{
109-
var sqlColumns = new StringBuilder();
110-
foreach (var field in modelDef.FieldDefinitions)
111-
{
112-
if (sqlColumns.Length > 0)
113-
sqlColumns.Append(", ");
114-
115-
sqlColumns.Append(OrmLiteConfig.DialectProvider.GetQuotedColumnName(field.FieldName));
116-
}
117-
118-
return sqlColumns.ToString();
108+
return OrmLiteConfig.DialectProvider.GetColumnNames(modelDef);
119109
}
120110

121111
internal static string GetIdsInSql(this IEnumerable idValues)

src/ServiceStack.OrmLite/OrmLiteWriteExtensions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,13 +383,18 @@ internal static int Update<T>(this IDbCommand dbCmd, T obj)
383383
if (OrmLiteConfig.UpdateFilter != null)
384384
OrmLiteConfig.UpdateFilter(dbCmd, obj);
385385

386-
OrmLiteConfig.DialectProvider.PrepareParameterizedUpdateStatement<T>(dbCmd);
386+
var hadRowVersion = OrmLiteConfig.DialectProvider.PrepareParameterizedUpdateStatement<T>(dbCmd);
387387
if (string.IsNullOrEmpty(dbCmd.CommandText))
388388
return 0;
389389

390390
OrmLiteConfig.DialectProvider.SetParameterValues<T>(dbCmd, obj);
391391

392-
return dbCmd.ExecNonQuery();
392+
var rowsUpdated = dbCmd.ExecNonQuery();
393+
394+
if (hadRowVersion && rowsUpdated == 0)
395+
throw new RowModifiedException();
396+
397+
return rowsUpdated;
393398
}
394399

395400
internal static int Update<T>(this IDbCommand dbCmd, params T[] objs)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
namespace ServiceStack.OrmLite
4+
{
5+
/// <summary>
6+
/// Thrown when an update to a table with optimistic concurrency column(s) fails.
7+
/// </summary>
8+
public class RowModifiedException : Exception
9+
{
10+
public RowModifiedException()
11+
{
12+
}
13+
public RowModifiedException(string message)
14+
: base(message)
15+
{
16+
}
17+
public RowModifiedException(string message, Exception innerException)
18+
: base(message, innerException)
19+
{
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)