Skip to content

Commit 3c124f0

Browse files
committed
Refactored to AdoAdapterUpserter
1 parent a445dd9 commit 3c124f0

34 files changed

Lines changed: 424 additions & 38 deletions

Simple.Data.Ado/AdoAdapter.IAdapterWithTransactions.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public int UpdateMany(string tableName, IEnumerable<IDictionary<string, object>>
5757

5858
public int Update(string tableName, IDictionary<string, object> data, IAdapterTransaction adapterTransaction)
5959
{
60-
string[] keyFieldNames = GetKeyFieldNames(tableName).ToArray();
60+
string[] keyFieldNames = GetKeyNames(tableName).ToArray();
6161
if (keyFieldNames.Length == 0) throw new AdoAdapterException("No Primary Key found for implicit update");
6262
return Update(tableName, data, GetCriteria(tableName, keyFieldNames, data), adapterTransaction);
6363
}
@@ -126,18 +126,19 @@ public int Delete(string tableName, SimpleExpression criteria, IAdapterTransacti
126126
public override IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired, IAdapterTransaction adapterTransaction)
127127
{
128128
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
129-
var finder = new AdoAdapterFinder(this, transaction);
130-
if (finder.FindOne(tableName, criteria) != null)
131-
{
132-
// Don't update columns used as criteria
133-
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
134-
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();
135-
136-
var commandBuilder = new UpdateHelper(_schema).GetUpdateCommand(tableName, data, criteria);
137-
Execute(commandBuilder, adapterTransaction);
138-
return resultRequired ? finder.FindOne(tableName, criteria) : null;
139-
}
140-
return new AdoAdapterInserter(this, transaction).Insert(tableName, data, resultRequired);
129+
return new AdoAdapterUpserter(this, transaction).Upsert(tableName, data, criteria, resultRequired);
130+
}
131+
132+
public override IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, IAdapterTransaction adapterTransaction, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
133+
{
134+
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
135+
return new AdoAdapterUpserter(this, transaction).UpsertMany(tableName, list, isResultRequired, errorCallback);
136+
}
137+
138+
public override IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, IEnumerable<string> keyFieldNames, IAdapterTransaction adapterTransaction, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
139+
{
140+
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
141+
return new AdoAdapterUpserter(this, transaction).UpsertMany(tableName, list, keyFieldNames.ToArray(), isResultRequired, errorCallback);
141142
}
142143
}
143144
}

Simple.Data.Ado/AdoAdapter.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public ISchemaProvider SchemaProvider
7979
public override IDictionary<string, object> GetKey(string tableName, IDictionary<string, object> record)
8080
{
8181
var homogenizedRecord = new Dictionary<string, object>(record, HomogenizedEqualityComparer.DefaultInstance);
82-
return GetKeyFieldNames(tableName).ToDictionary(key => key,
82+
return GetKeyNames(tableName).ToDictionary(key => key,
8383
key => homogenizedRecord.ContainsKey(key) ? homogenizedRecord[key] : null);
8484
}
8585

@@ -233,9 +233,9 @@ public override int Delete(string tableName, SimpleExpression criteria)
233233
/// </summary>
234234
/// <param name="tableName">Name of the table.</param>
235235
/// <returns>A list of field names; an empty list if no key is defined.</returns>
236-
public IEnumerable<string> GetKeyFieldNames(string tableName)
236+
public override IList<string> GetKeyNames(string tableName)
237237
{
238-
return _schema.FindTable(tableName).PrimaryKey.AsEnumerable();
238+
return _schema.FindTable(tableName).PrimaryKey.AsEnumerable().ToList();
239239
}
240240

241241
private int Execute(ICommandBuilder commandBuilder)
@@ -250,7 +250,8 @@ private int Execute(ICommandBuilder commandBuilder)
250250
}
251251
}
252252
}
253-
private int Execute(ICommandBuilder commandBuilder, IDbConnection connection)
253+
254+
internal static int Execute(ICommandBuilder commandBuilder, IDbConnection connection)
254255
{
255256
using (connection.MaybeDisposable())
256257
{
@@ -262,9 +263,14 @@ private int Execute(ICommandBuilder commandBuilder, IDbConnection connection)
262263
}
263264
}
264265

265-
private static int Execute(ICommandBuilder commandBuilder, IAdapterTransaction transaction)
266+
internal static int Execute(ICommandBuilder commandBuilder, IAdapterTransaction transaction)
266267
{
267268
IDbTransaction dbTransaction = ((AdoAdapterTransaction) transaction).Transaction;
269+
return Execute(commandBuilder, dbTransaction);
270+
}
271+
272+
internal static int Execute(ICommandBuilder commandBuilder, IDbTransaction dbTransaction)
273+
{
268274
using (IDbCommand command = commandBuilder.GetCommand(dbTransaction.Connection))
269275
{
270276
command.Transaction = dbTransaction;
@@ -307,23 +313,17 @@ public DatabaseSchema GetSchema()
307313

308314
public override IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired)
309315
{
310-
var connection = CreateConnection();
311-
using (connection.MaybeDisposable())
312-
{
313-
connection.OpenIfClosed();
314-
var finder = new AdoAdapterFinder(this, connection);
315-
if (finder.FindOne(tableName, criteria) != null)
316-
{
317-
// Don't update columns used as criteria
318-
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
319-
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();
316+
return new AdoAdapterUpserter(this).Upsert(tableName, data, criteria, resultRequired);
317+
}
320318

321-
var commandBuilder = new UpdateHelper(_schema).GetUpdateCommand(tableName, data, criteria);
322-
Execute(commandBuilder, connection);
323-
return resultRequired ? finder.FindOne(tableName, criteria) : null;
324-
}
325-
return new AdoAdapterInserter(this, connection).Insert(tableName, data, resultRequired);
326-
}
319+
public override IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
320+
{
321+
return new AdoAdapterUpserter(this).UpsertMany(tableName, list, isResultRequired, errorCallback);
322+
}
323+
324+
public override IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, IEnumerable<string> keyFieldNames, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
325+
{
326+
return new AdoAdapterUpserter(this).UpsertMany(tableName, list, keyFieldNames.ToArray(), isResultRequired, errorCallback);
327327
}
328328

329329
public string GetIdentityFunction()
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
namespace Simple.Data.Ado
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Data;
6+
using System.Linq;
7+
using Extensions;
8+
9+
class AdoAdapterUpserter
10+
{
11+
private readonly AdoAdapter _adapter;
12+
private readonly IDbConnection _connection;
13+
private readonly IDbTransaction _transaction;
14+
15+
public AdoAdapterUpserter(AdoAdapter adapter) : this(adapter, (IDbTransaction)null)
16+
{
17+
}
18+
19+
public AdoAdapterUpserter(AdoAdapter adapter, IDbConnection connection)
20+
{
21+
_adapter = adapter;
22+
_connection = connection;
23+
}
24+
25+
public AdoAdapterUpserter(AdoAdapter adapter, IDbTransaction transaction)
26+
{
27+
_adapter = adapter;
28+
_transaction = transaction;
29+
if (transaction != null) _connection = transaction.Connection;
30+
}
31+
32+
public IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired)
33+
{
34+
var connection = _connection ?? _adapter.CreateConnection();
35+
using (connection.MaybeDisposable())
36+
{
37+
connection.OpenIfClosed();
38+
return Upsert(tableName, data, criteria, resultRequired, connection);
39+
}
40+
}
41+
42+
private IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired,
43+
IDbConnection connection)
44+
{
45+
var finder = _transaction == null
46+
? new AdoAdapterFinder(_adapter, connection)
47+
: new AdoAdapterFinder(_adapter, _transaction);
48+
if (finder.FindOne(tableName, criteria) != null)
49+
{
50+
// Don't update columns used as criteria
51+
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
52+
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();
53+
54+
var commandBuilder = new UpdateHelper(_adapter.GetSchema()).GetUpdateCommand(tableName, data, criteria);
55+
if (_transaction == null)
56+
{
57+
AdoAdapter.Execute(commandBuilder, connection);
58+
}
59+
else
60+
{
61+
AdoAdapter.Execute(commandBuilder, _transaction);
62+
}
63+
return resultRequired ? finder.FindOne(tableName, criteria) : null;
64+
}
65+
var inserter = _transaction == null
66+
? new AdoAdapterInserter(_adapter, connection)
67+
: new AdoAdapterInserter(_adapter, _transaction);
68+
return inserter.Insert(tableName, data, resultRequired);
69+
}
70+
71+
72+
public IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
73+
{
74+
foreach (var row in list)
75+
{
76+
IDictionary<string, object> result;
77+
try
78+
{
79+
var criteria = ExpressionHelper.CriteriaDictionaryToExpression(tableName,
80+
_adapter.GetKey(tableName, row));
81+
result = Upsert(tableName, row, criteria, isResultRequired);
82+
}
83+
catch (Exception ex)
84+
{
85+
if (errorCallback(row, ex)) continue;
86+
throw;
87+
}
88+
89+
yield return result;
90+
}
91+
}
92+
93+
public IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, IList<string> keyFieldNames, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
94+
{
95+
foreach (var row in list)
96+
{
97+
IDictionary<string, object> result;
98+
try
99+
{
100+
var criteria = GetCriteria(tableName, keyFieldNames, row);
101+
result = Upsert(tableName, row, criteria, isResultRequired);
102+
}
103+
catch (Exception ex)
104+
{
105+
if (errorCallback(row, ex)) continue;
106+
throw;
107+
}
108+
109+
yield return result;
110+
}
111+
}
112+
113+
private static SimpleExpression GetCriteria(string tableName, IEnumerable<string> criteriaFieldNames,
114+
IDictionary<string, object> record)
115+
{
116+
var criteria = new Dictionary<string, object>();
117+
118+
foreach (var criteriaFieldName in criteriaFieldNames)
119+
{
120+
var name = criteriaFieldName;
121+
var keyValuePair = record.SingleOrDefault(kvp => kvp.Key.Homogenize().Equals(name.Homogenize()));
122+
if (string.IsNullOrWhiteSpace(keyValuePair.Key))
123+
{
124+
throw new InvalidOperationException("Key field value not set.");
125+
}
126+
127+
criteria.Add(criteriaFieldName, keyValuePair.Value);
128+
record.Remove(keyValuePair);
129+
}
130+
return ExpressionHelper.CriteriaDictionaryToExpression(tableName, criteria);
131+
}
132+
}
133+
}

Simple.Data.Ado/BulkUpdater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class BulkUpdater : IBulkUpdater
1212
{
1313
public int Update(AdoAdapter adapter, string tableName, IList<IDictionary<string, object>> data, IDbTransaction transaction)
1414
{
15-
return Update(adapter, tableName, data, adapter.GetKeyFieldNames(tableName).ToList(), transaction);
15+
return Update(adapter, tableName, data, adapter.GetKeyNames(tableName).ToList(), transaction);
1616
}
1717

1818
public int Update(AdoAdapter adapter, string tableName, IList<IDictionary<string, object>> data, IEnumerable<string> criteriaFieldNames, IDbTransaction transaction)

Simple.Data.Ado/Simple.Data.Ado.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<Compile Include="AdoAdapterQueryRunner.cs" />
6464
<Compile Include="AdoAdapterRelatedFinder.cs" />
6565
<Compile Include="AdoAdapterTransaction.cs" />
66+
<Compile Include="AdoAdapterUpserter.cs" />
6667
<Compile Include="BulkInserter.cs" />
6768
<Compile Include="BulkInserterHelper.cs" />
6869
<Compile Include="BulkInserterTransactionHelper.cs" />

Simple.Data.Mocking/XmlMockAdapter.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public override IDictionary<string, object> GetKey(string tableName, IDictionary
3333
key => record.ContainsKey(key) ? record[key] : null);
3434
}
3535

36+
public override IList<string> GetKeyNames(string tableName)
37+
{
38+
return GetKeyFieldNames(tableName).ToList();
39+
}
40+
3641
public override IDictionary<string, object> Get(string tableName, params object[] keyValues)
3742
{
3843
throw new NotImplementedException();

Simple.Data.SqlTest/FindTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
namespace Simple.Data.SqlTest
1212
{
13+
using System;
14+
1315
/// <summary>
1416
/// Summary description for FindTests
1517
/// </summary>
@@ -172,5 +174,35 @@ public void FindByWithNamedParameter()
172174
Assert.IsNotNull(user);
173175

174176
}
177+
178+
[Test]
179+
public void WithClauseShouldCastToStaticTypeWithCollection()
180+
{
181+
var db = DatabaseHelper.Open();
182+
Customer actual = db.Customers.WithOrders().FindByCustomerId(1);
183+
Assert.IsNotNull(actual);
184+
Assert.AreEqual(1, actual.Orders.Single().OrderId);
185+
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
186+
}
187+
188+
[Test]
189+
public void NamedParameterAndWithClauseShouldCastToStaticTypeWithCollection()
190+
{
191+
var db = DatabaseHelper.Open();
192+
Customer actual = db.Customers.WithOrders().FindBy(CustomerId: 1);
193+
Assert.IsNotNull(actual);
194+
Assert.AreEqual(1, actual.Orders.Single().OrderId);
195+
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
196+
}
197+
198+
[Test]
199+
public void ExpressionAndWithClauseShouldCastToStaticTypeWithCollection()
200+
{
201+
var db = DatabaseHelper.Open();
202+
Customer actual = db.Customers.WithOrders().Find(db.Customers.CustomerId == 1);
203+
Assert.IsNotNull(actual);
204+
Assert.AreEqual(1, actual.Orders.Single().OrderId);
205+
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
206+
}
175207
}
176208
}

Simple.Data.SqlTest/GetTests.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Simple.Data.SqlTest
44
{
5+
using System;
6+
using System.Linq;
7+
58
[TestFixture]
69
public class GetTests
710
{
@@ -14,9 +17,30 @@ public void Setup()
1417
[Test]
1518
public void TestGet()
1619
{
17-
var db = DatabaseHelper.Open();
18-
var user = db.Users.Get(1);
19-
Assert.AreEqual(1, user.Id);
20+
var db = DatabaseHelper.Open();
21+
var user = db.Users.Get(1);
22+
Assert.AreEqual(1, user.Id);
23+
}
24+
25+
[Test]
26+
public void WithClauseShouldCastToStaticTypeWithComplexProperty()
27+
{
28+
var db = DatabaseHelper.Open();
29+
Order actual = db.Orders.WithCustomer().Get(1);
30+
Assert.IsNotNull(actual);
31+
Assert.IsNotNull(actual.Customer);
32+
Assert.AreEqual("Test", actual.Customer.Name);
33+
Assert.AreEqual("100 Road", actual.Customer.Address);
34+
}
35+
36+
[Test]
37+
public void WithClauseShouldCastToStaticTypeWithCollection()
38+
{
39+
var db = DatabaseHelper.Open();
40+
Customer actual = db.Customers.WithOrders().Get(1);
41+
Assert.IsNotNull(actual);
42+
Assert.AreEqual(1, actual.Orders.Single().OrderId);
43+
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
2044
}
2145
}
2246
}

0 commit comments

Comments
 (0)