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

Commit 2670b3c

Browse files
committed
Change Delete API to remove null conditions in parameterized queries and into filter
1 parent 7c9acc6 commit 2670b3c

14 files changed

+154
-74
lines changed

src/ServiceStack.OrmLite/Async/OrmLiteWriteCommandExtensionsAsync.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,17 @@ private static Task<int> AssertRowsUpdatedAsync(IDbCommand dbCmd, bool hadRowVer
114114
});
115115
}
116116

117+
internal static Task<int> DeleteAsync<T>(this IDbCommand dbCmd, T filter, CancellationToken token)
118+
{
119+
return dbCmd.DeleteAsync<T>((object)filter, token);
120+
}
121+
117122
internal static Task<int> DeleteAsync<T>(this IDbCommand dbCmd, object anonType, CancellationToken token)
118123
{
119124
var dialectProvider = dbCmd.GetDialectProvider();
120-
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, anonType.AllFields<T>());
125+
126+
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(
127+
dbCmd, anonType.AllFieldsMap<T>());
121128

122129
dialectProvider.SetParameterValues<T>(dbCmd, anonType);
123130

@@ -127,30 +134,31 @@ internal static Task<int> DeleteAsync<T>(this IDbCommand dbCmd, object anonType,
127134
internal static Task<int> DeleteNonDefaultsAsync<T>(this IDbCommand dbCmd, T filter, CancellationToken token)
128135
{
129136
var dialectProvider = dbCmd.GetDialectProvider();
130-
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, filter.NonDefaultFields<T>());
137+
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(
138+
dbCmd, filter.AllFieldsMap<T>().NonDefaultsOnly());
131139

132140
dialectProvider.SetParameterValues<T>(dbCmd, filter);
133141

134142
return AssertRowsUpdatedAsync(dbCmd, hadRowVersion, token);
135143
}
136144

137-
internal static Task<int> DeleteAsync<T>(this IDbCommand dbCmd, CancellationToken token, params object[] objs)
145+
internal static Task<int> DeleteAsync<T>(this IDbCommand dbCmd, CancellationToken token, params T[] objs)
138146
{
139147
if (objs.Length == 0)
140148
return TaskResult.Zero;
141149

142-
return DeleteAllAsync<T>(dbCmd, objs[0].AllFields<T>(), objs, token);
150+
return DeleteAllAsync(dbCmd, objs, fieldValuesFn:null, token: token);
143151
}
144152

145153
internal static Task<int> DeleteNonDefaultsAsync<T>(this IDbCommand dbCmd, CancellationToken token, params T[] filters)
146154
{
147155
if (filters.Length == 0)
148156
return TaskResult.Zero;
149157

150-
return DeleteAllAsync<T>(dbCmd, filters[0].NonDefaultFields<T>(), filters.Map(x => (object)x), token);
158+
return DeleteAllAsync(dbCmd, filters, o => o.AllFieldsMap<T>().NonDefaultsOnly(), token);
151159
}
152160

153-
private static Task<int> DeleteAllAsync<T>(IDbCommand dbCmd, ICollection<string> deleteFields, IEnumerable<object> objs, CancellationToken token)
161+
private static Task<int> DeleteAllAsync<T>(IDbCommand dbCmd, IEnumerable<T> objs, Func<object, Dictionary<string, object>> fieldValuesFn = null, CancellationToken token=default(CancellationToken))
154162
{
155163
IDbTransaction dbTrans = null;
156164

@@ -159,11 +167,17 @@ private static Task<int> DeleteAllAsync<T>(IDbCommand dbCmd, ICollection<string>
159167
dbCmd.Transaction = dbTrans = dbCmd.Connection.BeginTransaction();
160168

161169
var dialectProvider = dbCmd.GetDialectProvider();
162-
dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, deleteFields);
163170

164171
return objs.EachAsync((obj, i) =>
165172
{
173+
var fieldValues = fieldValuesFn != null
174+
? fieldValuesFn(obj)
175+
: obj.AllFieldsMap<T>();
176+
177+
dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, fieldValues);
178+
166179
dialectProvider.SetParameterValues<T>(dbCmd, obj);
180+
167181
return dbCmd.ExecNonQueryAsync(token)
168182
.Then(rowsAffected => count += rowsAffected);
169183
})

src/ServiceStack.OrmLite/IOrmLiteDialectProvider.cs

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

8585
bool PrepareParameterizedUpdateStatement<T>(IDbCommand cmd, ICollection<string> updateFields = null);
8686

87-
bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, ICollection<string> deleteFields = null);
87+
bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IDictionary<string, object> delteFieldValues);
8888

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

src/ServiceStack.OrmLite/OrmLiteDialectProviderBase.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -628,12 +628,14 @@ public virtual void AppendFieldConditionFmt(StringBuilder sqlFilter, FieldDefini
628628
fieldDef.GetQuotedValue(objWithProperties, this));
629629
}
630630

631-
public virtual bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, ICollection<string> deleteFields = null)
631+
public virtual bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IDictionary<string, object> deleteFields)
632632
{
633+
if (deleteFields == null || deleteFields.Count == 0)
634+
throw new ArgumentException("DELETE's must have at least 1 criteria");
635+
633636
var sqlFilter = new StringBuilder();
634637
var modelDef = typeof(T).GetModelDefinition();
635638
var hadRowVesion = false;
636-
var hasSpecificFilter = deleteFields != null && deleteFields.Count > 0;
637639

638640
cmd.Parameters.Clear();
639641
cmd.CommandTimeout = OrmLiteConfig.CommandTimeout;
@@ -643,7 +645,9 @@ public virtual bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IColl
643645
if (fieldDef.ShouldSkipDelete())
644646
continue;
645647

646-
if (!fieldDef.IsRowVersion && (hasSpecificFilter && !deleteFields.Contains(fieldDef.Name)))
648+
object fieldValue;
649+
650+
if (!deleteFields.TryGetValue(fieldDef.Name, out fieldValue))
647651
continue;
648652

649653
if (fieldDef.IsRowVersion)
@@ -654,7 +658,16 @@ public virtual bool PrepareParameterizedDeleteStatement<T>(IDbCommand cmd, IColl
654658
if (sqlFilter.Length > 0)
655659
sqlFilter.Append(" AND ");
656660

657-
AppendFieldCondition(sqlFilter, fieldDef, cmd);
661+
if (fieldValue != null)
662+
{
663+
AppendFieldCondition(sqlFilter, fieldDef, cmd);
664+
}
665+
else
666+
{
667+
sqlFilter
668+
.Append(GetQuotedColumnName(fieldDef.FieldName))
669+
.Append(" IS NULL");
670+
}
658671
}
659672
catch (Exception ex)
660673
{

src/ServiceStack.OrmLite/OrmLiteReadCommandExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,23 @@ internal static Dictionary<string, object> AllFieldsMap<T>(this object anonType)
214214
return ret;
215215
}
216216

217+
internal static Dictionary<string, object> NonDefaultsOnly(this Dictionary<string, object> fieldValues)
218+
{
219+
var map = new Dictionary<string, object>();
220+
foreach (var entry in fieldValues)
221+
{
222+
if (entry.Value != null)
223+
{
224+
var type = entry.Value.GetType();
225+
if (!type.IsValueType || !entry.Value.Equals(type.GetDefaultValue()))
226+
{
227+
map[entry.Key] = entry.Value;
228+
}
229+
}
230+
}
231+
return map;
232+
}
233+
217234
internal static List<string> NonDefaultFields<T>(this object anonType)
218235
{
219236
var ret = new List<string>();

src/ServiceStack.OrmLite/OrmLiteWriteApi.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,14 @@ public static int Delete<T>(this IDbConnection dbConn, object anonFilter)
9393
return dbConn.Exec(dbCmd => dbCmd.Delete<T>(anonFilter));
9494
}
9595

96-
/// <summary>
97-
/// Delete 1 or more rows in a transaction using an anonymous type filter. E.g:
98-
/// <para>db.Delete&lt;Person&gt;(new { FirstName = "Jimi", Age = 27 }, new { FirstName = "Janis", Age = 27 })</para>
99-
/// </summary>
100-
public static int Delete<T>(this IDbConnection dbConn, params object[] anonFilters)
101-
{
102-
return dbConn.Exec(dbCmd => dbCmd.Delete<T>(anonFilters));
103-
}
104-
10596
/// <summary>
10697
/// Delete 1 row using all fields in the filter. E.g:
10798
/// <para>db.Delete(new Person { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27 })</para>
10899
/// </summary>
109100
/// <returns>number of rows deleted</returns>
110101
public static int Delete<T>(this IDbConnection dbConn, T allFieldsFilter)
111102
{
112-
return dbConn.Exec(dbCmd => dbCmd.Delete<T>(allFieldsFilter));
103+
return dbConn.Exec(dbCmd => dbCmd.Delete(allFieldsFilter));
113104
}
114105

115106
/// <summary>
@@ -118,7 +109,7 @@ public static int Delete<T>(this IDbConnection dbConn, T allFieldsFilter)
118109
/// </summary>
119110
public static int Delete<T>(this IDbConnection dbConn, params T[] allFieldsFilters)
120111
{
121-
return dbConn.Exec(dbCmd => dbCmd.Delete<T>(allFieldsFilters));
112+
return dbConn.Exec(dbCmd => dbCmd.Delete(allFieldsFilters));
122113
}
123114

124115
/// <summary>

src/ServiceStack.OrmLite/OrmLiteWriteApiAsync.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,14 @@ public static Task<int> UpdateAsync<T>(this IDbConnection dbConn, params T[] obj
9898
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync<T>(anonFilter, token));
9999
}
100100

101-
/// <summary>
102-
/// Delete 1 or more rows in a transaction using an anonymous type filter. E.g:
103-
/// <para>db.Delete&lt;Person&gt;(new { FirstName = "Jimi", Age = 27 }, new { FirstName = "Janis", Age = 27 })</para>
104-
/// </summary>
105-
public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, CancellationToken token, params object[] anonFilters)
106-
{
107-
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync<T>(token, anonFilters));
108-
}
109-
public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, params object[] anonFilters)
110-
{
111-
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync<T>(default(CancellationToken), anonFilters));
112-
}
113-
114101
/// <summary>
115102
/// Delete 1 row using all fields in the filter. E.g:
116103
/// <para>db.Delete(new Person { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27 })</para>
117104
/// </summary>
118105
/// <returns>number of rows deleted</returns>
119106
public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, T allFieldsFilter, CancellationToken token = default(CancellationToken))
120107
{
121-
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync<T>(allFieldsFilter, token));
108+
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync(allFieldsFilter, token));
122109
}
123110

124111
/// <summary>
@@ -127,7 +114,11 @@ public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, params object[
127114
/// </summary>
128115
public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, CancellationToken token = default(CancellationToken), params T[] allFieldsFilters)
129116
{
130-
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync<T>(token, allFieldsFilters));
117+
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync(token, allFieldsFilters));
118+
}
119+
public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, params T[] allFieldsFilters)
120+
{
121+
return dbConn.Exec(dbCmd => dbCmd.DeleteAsync(default(CancellationToken), allFieldsFilters));
131122
}
132123

133124
/// <summary>
@@ -137,7 +128,7 @@ public static Task<int> DeleteAsync<T>(this IDbConnection dbConn, params object[
137128
/// <returns>number of rows deleted</returns>
138129
public static Task<int> DeleteNonDefaultsAsync<T>(this IDbConnection dbConn, T nonDefaultsFilter, CancellationToken token = default(CancellationToken))
139130
{
140-
return dbConn.Exec(dbCmd => dbCmd.DeleteNonDefaultsAsync(token, nonDefaultsFilter));
131+
return dbConn.Exec(dbCmd => dbCmd.DeleteNonDefaultsAsync(nonDefaultsFilter, token));
141132
}
142133

143134
/// <summary>

src/ServiceStack.OrmLite/OrmLiteWriteCommandExtensions.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,17 @@ private static int AssertRowsUpdated(IDbCommand dbCmd, bool hadRowVersion)
469469
return rowsUpdated;
470470
}
471471

472+
internal static int Delete<T>(this IDbCommand dbCmd, T anonType)
473+
{
474+
return dbCmd.Delete<T>((object)anonType);
475+
}
476+
472477
internal static int Delete<T>(this IDbCommand dbCmd, object anonType)
473478
{
474479
var dialectProvider = dbCmd.GetDialectProvider();
475-
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, anonType.AllFields<T>());
480+
481+
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(
482+
dbCmd, anonType.AllFieldsMap<T>());
476483

477484
dialectProvider.SetParameterValues<T>(dbCmd, anonType);
478485

@@ -482,28 +489,29 @@ internal static int Delete<T>(this IDbCommand dbCmd, object anonType)
482489
internal static int DeleteNonDefaults<T>(this IDbCommand dbCmd, T filter)
483490
{
484491
var dialectProvider = dbCmd.GetDialectProvider();
485-
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, filter.NonDefaultFields<T>());
492+
var hadRowVersion = dialectProvider.PrepareParameterizedDeleteStatement<T>(
493+
dbCmd, filter.AllFieldsMap<T>().NonDefaultsOnly());
486494

487495
dialectProvider.SetParameterValues<T>(dbCmd, filter);
488496

489497
return AssertRowsUpdated(dbCmd, hadRowVersion);
490498
}
491499

492-
internal static int Delete<T>(this IDbCommand dbCmd, params object[] objs)
500+
internal static int Delete<T>(this IDbCommand dbCmd, T[] objs)
493501
{
494502
if (objs.Length == 0) return 0;
495503

496-
return DeleteAll<T>(dbCmd, objs[0].AllFields<T>(), objs);
504+
return DeleteAll(dbCmd, objs);
497505
}
498506

499-
internal static int DeleteNonDefaults<T>(this IDbCommand dbCmd, params T[] filters)
507+
internal static int DeleteNonDefaults<T>(this IDbCommand dbCmd, T[] filters)
500508
{
501509
if (filters.Length == 0) return 0;
502510

503-
return DeleteAll<T>(dbCmd, filters[0].NonDefaultFields<T>(), filters.Map(x => (object)x));
511+
return DeleteAll(dbCmd, filters, o => o.AllFieldsMap<T>().NonDefaultsOnly());
504512
}
505513

506-
private static int DeleteAll<T>(IDbCommand dbCmd, ICollection<string> deleteFields, IEnumerable<object> objs)
514+
private static int DeleteAll<T>(IDbCommand dbCmd, IEnumerable<T> objs, Func<object,Dictionary<string,object>> fieldValuesFn=null)
507515
{
508516
IDbTransaction dbTrans = null;
509517

@@ -515,10 +523,14 @@ private static int DeleteAll<T>(IDbCommand dbCmd, ICollection<string> deleteFiel
515523

516524
var dialectProvider = dbCmd.GetDialectProvider();
517525

518-
dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, deleteFields);
519-
520526
foreach (var obj in objs)
521527
{
528+
var fieldValues = fieldValuesFn != null
529+
? fieldValuesFn(obj)
530+
: obj.AllFieldsMap<T>();
531+
532+
dialectProvider.PrepareParameterizedDeleteStatement<T>(dbCmd, fieldValues);
533+
522534
dialectProvider.SetParameterValues<T>(dbCmd, obj);
523535

524536
count += dbCmd.ExecNonQuery();

tests/ServiceStack.OrmLite.Tests/ApiSqlServerTests.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,6 @@ public void API_SqlServer_Examples()
303303
db.Delete<Person>(new { FirstName = "Jimi", Age = 27 });
304304
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"FirstName\"=@FirstName AND \"Age\"=@Age"));
305305

306-
db.Delete<Person>(new { FirstName = "Jimi", Age = 27 },
307-
new { FirstName = "Janis", Age = 27 });
308-
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"FirstName\"=@FirstName AND \"Age\"=@Age"));
309-
310306
db.Delete(new Person { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27 });
311307
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"Id\"=@Id AND \"FirstName\"=@FirstName AND \"LastName\"=@LastName AND \"Age\"=@Age"));
312308

tests/ServiceStack.OrmLite.Tests/ApiSqliteTests.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,6 @@ public void API_Sqlite_Examples()
308308
db.Delete<Person>(new { FirstName = "Jimi", Age = 27 });
309309
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"FirstName\"=@FirstName AND \"Age\"=@Age"));
310310

311-
db.Delete<Person>(new { FirstName = "Jimi", Age = 27 },
312-
new { FirstName = "Janis", Age = 27 });
313-
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"FirstName\"=@FirstName AND \"Age\"=@Age"));
314-
315311
db.Delete(new Person { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27 });
316312
Assert.That(db.GetLastSql(), Is.EqualTo("DELETE FROM \"Person\" WHERE \"Id\"=@Id AND \"FirstName\"=@FirstName AND \"LastName\"=@LastName AND \"Age\"=@Age"));
317313

tests/ServiceStack.OrmLite.Tests/Issues/JoinsWithSchemas.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
namespace ServiceStack.OrmLite.Tests.Issues
66
{
7-
[Schema("schema1")]
7+
[Schema("Schema")]
88
public class Entity1
99
{
1010
public int Id { get; set; }
1111

1212
public int Entity2Fk { get; set; }
1313
}
1414

15-
[Schema("schema1")]
15+
[Schema("Schema")]
1616
public class Entity2
1717
{
1818
public int Id { get; set; }

0 commit comments

Comments
 (0)