Skip to content

Commit 55b474d

Browse files
committed
Added Update overloads which take an 'original values' object or list of objects, for optimistic concurrency
1 parent 51b12b0 commit 55b474d

5 files changed

Lines changed: 156 additions & 2 deletions

File tree

Simple.Data.BehaviourTest/UpdateTest.cs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,43 @@ public void TestUpdateWithDynamicObject()
4848
Parameter(0).Is("Steve");
4949
Parameter(1).Is(50);
5050
Parameter(2).Is(1);
51-
}
51+
}
52+
53+
[Test]
54+
public void TestUpdateWithDynamicObjectAndOriginalValues()
55+
{
56+
dynamic newRecord = new SimpleRecord();
57+
newRecord.Id = 1;
58+
newRecord.Name = "Steve";
59+
newRecord.Age = 50;
60+
dynamic originalRecord = new SimpleRecord();
61+
originalRecord.Id = 2;
62+
originalRecord.Name = "Steve";
63+
originalRecord.Age = 50;
64+
65+
_db.Users.Update(newRecord, originalRecord);
66+
GeneratedSqlIs("update [dbo].[Users] set [Id] = @p1 where [dbo].[Users].[Id] = @p2");
67+
Parameter(0).Is(1);
68+
Parameter(1).Is(2);
69+
}
70+
71+
[Test]
72+
public void TestUpdateWithDynamicObjectsAndOriginalValues()
73+
{
74+
dynamic newRecord = new SimpleRecord();
75+
newRecord.Id = 1;
76+
newRecord.Name = "Steve";
77+
newRecord.Age = 50;
78+
dynamic originalRecord = new SimpleRecord();
79+
originalRecord.Id = 2;
80+
originalRecord.Name = "Steve";
81+
originalRecord.Age = 50;
82+
83+
_db.Users.Update(new[] {newRecord}, new[] {originalRecord});
84+
GeneratedSqlIs("update [dbo].[Users] set [Id] = @p1 where [dbo].[Users].[Id] = @p2");
85+
Parameter(0).Is(1);
86+
Parameter(1).Is(2);
87+
}
5288

5389
[Test]
5490
public void TestUpdateWithDynamicObjectList()
@@ -118,6 +154,40 @@ public void TestUpdateWithStaticObject()
118154
Parameter(3).Is(1);
119155
}
120156

157+
[Test]
158+
public void TestUpdateWithStaticObjectAndOriginalObject()
159+
{
160+
var newUser = new User
161+
{
162+
Id = 1,
163+
Name = "Steve",
164+
Age = 50
165+
};
166+
var originalUser = new User() {Id = 2, Name = "Steve", Age = 50};
167+
_db.Users.Update(newUser, originalUser);
168+
GeneratedSqlIs(
169+
"update [dbo].[Users] set [Id] = @p1 where [dbo].[Users].[Id] = @p2");
170+
Parameter(0).Is(1);
171+
Parameter(1).Is(2);
172+
}
173+
174+
[Test]
175+
public void TestUpdateWithStaticObjectsAndOriginalObject()
176+
{
177+
var newUser = new User
178+
{
179+
Id = 1,
180+
Name = "Steve",
181+
Age = 50
182+
};
183+
var originalUser = new User() { Id = 2, Name = "Steve", Age = 50 };
184+
_db.Users.Update(new[] {newUser}, new[] {originalUser});
185+
GeneratedSqlIs(
186+
"update [dbo].[Users] set [Id] = @p1 where [dbo].[Users].[Id] = @p2");
187+
Parameter(0).Is(1);
188+
Parameter(1).Is(2);
189+
}
190+
121191
[Test]
122192
public void TestUpdateWithStaticObjectWithShoutyCase()
123193
{

Simple.Data/Commands/UpdateCommand.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,35 @@ public bool IsCommandFor(string method)
1919

2020
public object Execute(DataStrategy dataStrategy, DynamicTable table, InvokeMemberBinder binder, object[] args)
2121
{
22-
if (args.Length != 1) throw new ArgumentException("Incorrect number of arguments to Update method.");
22+
if (args.Length == 0 || args.Length > 2) throw new ArgumentException("Incorrect number of arguments to Update method.");
2323

24+
if (args.Length == 1)
25+
{
26+
return UpdateUsingKeys(dataStrategy, table, args);
27+
}
28+
29+
return UpdateUsingOriginalValues(dataStrategy, table, args);
30+
}
31+
32+
private static object UpdateUsingOriginalValues(DataStrategy dataStrategy, DynamicTable table, object[] args)
33+
{
34+
var newValues = ObjectToDictionary(args[0]);
35+
var newValuesList = newValues as IList<IDictionary<string, object>>;
36+
if (newValuesList != null)
37+
{
38+
var originalValuesList = ObjectToDictionary(args[1]) as IList<IDictionary<string, object>>;
39+
if (originalValuesList == null) throw new InvalidOperationException("Parameter type mismatch; both parameters to Update should be same type.");
40+
return dataStrategy.UpdateMany(table.GetQualifiedName(), newValuesList, originalValuesList);
41+
}
42+
43+
var newValuesDict = newValues as IDictionary<string, object>;
44+
var originalValuesDict = ObjectToDictionary(args[1]) as IDictionary<string, object>;
45+
if (originalValuesDict == null) throw new InvalidOperationException("Parameter type mismatch; both parameters to Update should be same type.");
46+
return dataStrategy.Update(table.GetQualifiedName(), newValuesDict, originalValuesDict);
47+
}
48+
49+
private static object UpdateUsingKeys(DataStrategy dataStrategy, DynamicTable table, object[] args)
50+
{
2451
var record = ObjectToDictionary(args[0]);
2552
var list = record as IList<IDictionary<string, object>>;
2653
if (list != null) return dataStrategy.UpdateMany(table.GetQualifiedName(), list);

Simple.Data/DataStrategy.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,28 @@ internal bool IsExpressionFunction(string name, object[] args)
135135
}
136136

137137
internal abstract int UpdateMany(string tableName, IList<IDictionary<string, object>> dataList, IEnumerable<string> criteriaFieldNames);
138+
139+
internal abstract int UpdateMany(string tableName, IList<IDictionary<string, object>> newValuesList,
140+
IList<IDictionary<string, object>> originalValuesList);
141+
142+
public abstract int Update(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict);
143+
144+
protected static SimpleExpression CreateCriteriaFromOriginalValues(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict)
145+
{
146+
var criteriaValues = originalValuesDict
147+
.Where(originalKvp => newValuesDict.ContainsKey(originalKvp.Key) && !(Equals(newValuesDict[originalKvp.Key], originalKvp.Value)));
148+
149+
return ExpressionHelper.CriteriaDictionaryToExpression(tableName, criteriaValues);
150+
}
151+
152+
protected static Dictionary<string, object> CreateChangedValuesDict(IEnumerable<KeyValuePair<string, object>> newValuesDict, IDictionary<string, object> originalValuesDict)
153+
{
154+
var changedValuesDict =
155+
newValuesDict.Where(
156+
kvp =>
157+
(!originalValuesDict.ContainsKey(kvp.Key)) || !(Equals(kvp.Value, originalValuesDict[kvp.Key])))
158+
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
159+
return changedValuesDict;
160+
}
138161
}
139162
}

Simple.Data/Database.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,23 @@ internal override int UpdateMany(string tableName, IList<IDictionary<string, obj
6868
return _adapter.UpdateMany(tableName, dataList, criteriaFieldNames);
6969
}
7070

71+
internal override int UpdateMany(string tableName, IList<IDictionary<string, object>> newValuesList, IList<IDictionary<string, object>> originalValuesList)
72+
{
73+
int count = 0;
74+
for (int i = 0; i < newValuesList.Count; i++)
75+
{
76+
count += Update(tableName, newValuesList[i], originalValuesList[i]);
77+
}
78+
return count;
79+
}
80+
81+
public override int Update(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict)
82+
{
83+
SimpleExpression criteria = CreateCriteriaFromOriginalValues(tableName, newValuesDict, originalValuesDict);
84+
var changedValuesDict = CreateChangedValuesDict(newValuesDict, originalValuesDict);
85+
return _adapter.Update(tableName, changedValuesDict, criteria);
86+
}
87+
7188
/// <summary>
7289
/// Finds data from the specified "table".
7390
/// </summary>

Simple.Data/SimpleTransaction.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ internal override int Update(string tableName, IDictionary<string, object> data)
135135
return _adapter.Update(tableName, data, AdapterTransaction);
136136
}
137137

138+
internal override int UpdateMany(string tableName, IList<IDictionary<string, object>> newValuesList, IList<IDictionary<string, object>> originalValuesList)
139+
{
140+
int count = 0;
141+
for (int i = 0; i < newValuesList.Count; i++)
142+
{
143+
count += Update(tableName, newValuesList[i], originalValuesList[i]);
144+
}
145+
return count;
146+
}
147+
148+
public override int Update(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict)
149+
{
150+
SimpleExpression criteria = CreateCriteriaFromOriginalValues(tableName, newValuesDict, originalValuesDict);
151+
var changedValuesDict = CreateChangedValuesDict(newValuesDict, originalValuesDict);
152+
return _adapter.Update(tableName, changedValuesDict, criteria, AdapterTransaction);
153+
}
154+
138155
internal override int Delete(string tableName, SimpleExpression criteria)
139156
{
140157
return _adapter.Delete(tableName, criteria, AdapterTransaction);

0 commit comments

Comments
 (0)