Skip to content

Commit

Permalink
Refactored to AdoAdapterUpserter
Browse files Browse the repository at this point in the history
  • Loading branch information
markrendle committed Feb 16, 2012
1 parent a445dd9 commit 3c124f0
Show file tree
Hide file tree
Showing 34 changed files with 424 additions and 38 deletions.
27 changes: 14 additions & 13 deletions Simple.Data.Ado/AdoAdapter.IAdapterWithTransactions.cs
Expand Up @@ -57,7 +57,7 @@ public IAdapterTransaction BeginTransaction(IsolationLevel isolationLevel, strin

public int Update(string tableName, IDictionary<string, object> data, IAdapterTransaction adapterTransaction)
{
string[] keyFieldNames = GetKeyFieldNames(tableName).ToArray();
string[] keyFieldNames = GetKeyNames(tableName).ToArray();
if (keyFieldNames.Length == 0) throw new AdoAdapterException("No Primary Key found for implicit update");
return Update(tableName, data, GetCriteria(tableName, keyFieldNames, data), adapterTransaction);
}
Expand Down Expand Up @@ -126,18 +126,19 @@ public int Delete(string tableName, SimpleExpression criteria, IAdapterTransacti
public override IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired, IAdapterTransaction adapterTransaction)
{
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
var finder = new AdoAdapterFinder(this, transaction);
if (finder.FindOne(tableName, criteria) != null)
{
// Don't update columns used as criteria
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();

var commandBuilder = new UpdateHelper(_schema).GetUpdateCommand(tableName, data, criteria);
Execute(commandBuilder, adapterTransaction);
return resultRequired ? finder.FindOne(tableName, criteria) : null;
}
return new AdoAdapterInserter(this, transaction).Insert(tableName, data, resultRequired);
return new AdoAdapterUpserter(this, transaction).Upsert(tableName, data, criteria, resultRequired);
}

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)
{
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
return new AdoAdapterUpserter(this, transaction).UpsertMany(tableName, list, isResultRequired, errorCallback);
}

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)
{
var transaction = ((AdoAdapterTransaction) adapterTransaction).Transaction;
return new AdoAdapterUpserter(this, transaction).UpsertMany(tableName, list, keyFieldNames.ToArray(), isResultRequired, errorCallback);
}
}
}
42 changes: 21 additions & 21 deletions Simple.Data.Ado/AdoAdapter.cs
Expand Up @@ -79,7 +79,7 @@ public ISchemaProvider SchemaProvider
public override IDictionary<string, object> GetKey(string tableName, IDictionary<string, object> record)
{
var homogenizedRecord = new Dictionary<string, object>(record, HomogenizedEqualityComparer.DefaultInstance);
return GetKeyFieldNames(tableName).ToDictionary(key => key,
return GetKeyNames(tableName).ToDictionary(key => key,
key => homogenizedRecord.ContainsKey(key) ? homogenizedRecord[key] : null);
}

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

private int Execute(ICommandBuilder commandBuilder)
Expand All @@ -250,7 +250,8 @@ private int Execute(ICommandBuilder commandBuilder)
}
}
}
private int Execute(ICommandBuilder commandBuilder, IDbConnection connection)

internal static int Execute(ICommandBuilder commandBuilder, IDbConnection connection)
{
using (connection.MaybeDisposable())
{
Expand All @@ -262,9 +263,14 @@ private int Execute(ICommandBuilder commandBuilder, IDbConnection connection)
}
}

private static int Execute(ICommandBuilder commandBuilder, IAdapterTransaction transaction)
internal static int Execute(ICommandBuilder commandBuilder, IAdapterTransaction transaction)
{
IDbTransaction dbTransaction = ((AdoAdapterTransaction) transaction).Transaction;
return Execute(commandBuilder, dbTransaction);
}

internal static int Execute(ICommandBuilder commandBuilder, IDbTransaction dbTransaction)
{
using (IDbCommand command = commandBuilder.GetCommand(dbTransaction.Connection))
{
command.Transaction = dbTransaction;
Expand Down Expand Up @@ -307,23 +313,17 @@ public DatabaseSchema GetSchema()

public override IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired)
{
var connection = CreateConnection();
using (connection.MaybeDisposable())
{
connection.OpenIfClosed();
var finder = new AdoAdapterFinder(this, connection);
if (finder.FindOne(tableName, criteria) != null)
{
// Don't update columns used as criteria
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();
return new AdoAdapterUpserter(this).Upsert(tableName, data, criteria, resultRequired);
}

var commandBuilder = new UpdateHelper(_schema).GetUpdateCommand(tableName, data, criteria);
Execute(commandBuilder, connection);
return resultRequired ? finder.FindOne(tableName, criteria) : null;
}
return new AdoAdapterInserter(this, connection).Insert(tableName, data, resultRequired);
}
public override IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
{
return new AdoAdapterUpserter(this).UpsertMany(tableName, list, isResultRequired, errorCallback);
}

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)
{
return new AdoAdapterUpserter(this).UpsertMany(tableName, list, keyFieldNames.ToArray(), isResultRequired, errorCallback);
}

public string GetIdentityFunction()
Expand Down
133 changes: 133 additions & 0 deletions Simple.Data.Ado/AdoAdapterUpserter.cs
@@ -0,0 +1,133 @@
namespace Simple.Data.Ado
{
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Extensions;

class AdoAdapterUpserter
{
private readonly AdoAdapter _adapter;
private readonly IDbConnection _connection;
private readonly IDbTransaction _transaction;

public AdoAdapterUpserter(AdoAdapter adapter) : this(adapter, (IDbTransaction)null)
{
}

public AdoAdapterUpserter(AdoAdapter adapter, IDbConnection connection)
{
_adapter = adapter;
_connection = connection;
}

public AdoAdapterUpserter(AdoAdapter adapter, IDbTransaction transaction)
{
_adapter = adapter;
_transaction = transaction;
if (transaction != null) _connection = transaction.Connection;
}

public IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired)
{
var connection = _connection ?? _adapter.CreateConnection();
using (connection.MaybeDisposable())
{
connection.OpenIfClosed();
return Upsert(tableName, data, criteria, resultRequired, connection);
}
}

private IDictionary<string, object> Upsert(string tableName, IDictionary<string, object> data, SimpleExpression criteria, bool resultRequired,
IDbConnection connection)
{
var finder = _transaction == null
? new AdoAdapterFinder(_adapter, connection)
: new AdoAdapterFinder(_adapter, _transaction);
if (finder.FindOne(tableName, criteria) != null)
{
// Don't update columns used as criteria
var keys = criteria.GetOperandsOfType<ObjectReference>().Select(o => o.GetName().Homogenize());
data = data.Where(kvp => keys.All(k => k != kvp.Key.Homogenize())).ToDictionary();

var commandBuilder = new UpdateHelper(_adapter.GetSchema()).GetUpdateCommand(tableName, data, criteria);
if (_transaction == null)
{
AdoAdapter.Execute(commandBuilder, connection);
}
else
{
AdoAdapter.Execute(commandBuilder, _transaction);
}
return resultRequired ? finder.FindOne(tableName, criteria) : null;
}
var inserter = _transaction == null
? new AdoAdapterInserter(_adapter, connection)
: new AdoAdapterInserter(_adapter, _transaction);
return inserter.Insert(tableName, data, resultRequired);
}


public IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, bool isResultRequired, Func<IDictionary<string, object>, Exception, bool> errorCallback)
{
foreach (var row in list)
{
IDictionary<string, object> result;
try
{
var criteria = ExpressionHelper.CriteriaDictionaryToExpression(tableName,
_adapter.GetKey(tableName, row));
result = Upsert(tableName, row, criteria, isResultRequired);
}
catch (Exception ex)
{
if (errorCallback(row, ex)) continue;
throw;
}

yield return result;
}
}

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)
{
foreach (var row in list)
{
IDictionary<string, object> result;
try
{
var criteria = GetCriteria(tableName, keyFieldNames, row);
result = Upsert(tableName, row, criteria, isResultRequired);
}
catch (Exception ex)
{
if (errorCallback(row, ex)) continue;
throw;
}

yield return result;
}
}

private static SimpleExpression GetCriteria(string tableName, IEnumerable<string> criteriaFieldNames,
IDictionary<string, object> record)
{
var criteria = new Dictionary<string, object>();

foreach (var criteriaFieldName in criteriaFieldNames)
{
var name = criteriaFieldName;
var keyValuePair = record.SingleOrDefault(kvp => kvp.Key.Homogenize().Equals(name.Homogenize()));
if (string.IsNullOrWhiteSpace(keyValuePair.Key))
{
throw new InvalidOperationException("Key field value not set.");
}

criteria.Add(criteriaFieldName, keyValuePair.Value);
record.Remove(keyValuePair);
}
return ExpressionHelper.CriteriaDictionaryToExpression(tableName, criteria);
}
}
}
2 changes: 1 addition & 1 deletion Simple.Data.Ado/BulkUpdater.cs
Expand Up @@ -12,7 +12,7 @@ class BulkUpdater : IBulkUpdater
{
public int Update(AdoAdapter adapter, string tableName, IList<IDictionary<string, object>> data, IDbTransaction transaction)
{
return Update(adapter, tableName, data, adapter.GetKeyFieldNames(tableName).ToList(), transaction);
return Update(adapter, tableName, data, adapter.GetKeyNames(tableName).ToList(), transaction);
}

public int Update(AdoAdapter adapter, string tableName, IList<IDictionary<string, object>> data, IEnumerable<string> criteriaFieldNames, IDbTransaction transaction)
Expand Down
1 change: 1 addition & 0 deletions Simple.Data.Ado/Simple.Data.Ado.csproj
Expand Up @@ -63,6 +63,7 @@
<Compile Include="AdoAdapterQueryRunner.cs" />
<Compile Include="AdoAdapterRelatedFinder.cs" />
<Compile Include="AdoAdapterTransaction.cs" />
<Compile Include="AdoAdapterUpserter.cs" />
<Compile Include="BulkInserter.cs" />
<Compile Include="BulkInserterHelper.cs" />
<Compile Include="BulkInserterTransactionHelper.cs" />
Expand Down
5 changes: 5 additions & 0 deletions Simple.Data.Mocking/XmlMockAdapter.cs
Expand Up @@ -33,6 +33,11 @@ public XElement Data
key => record.ContainsKey(key) ? record[key] : null);
}

public override IList<string> GetKeyNames(string tableName)
{
return GetKeyFieldNames(tableName).ToList();
}

public override IDictionary<string, object> Get(string tableName, params object[] keyValues)
{
throw new NotImplementedException();
Expand Down
32 changes: 32 additions & 0 deletions Simple.Data.SqlTest/FindTests.cs
Expand Up @@ -10,6 +10,8 @@

namespace Simple.Data.SqlTest
{
using System;

/// <summary>
/// Summary description for FindTests
/// </summary>
Expand Down Expand Up @@ -172,5 +174,35 @@ public void FindByWithNamedParameter()
Assert.IsNotNull(user);

}

[Test]
public void WithClauseShouldCastToStaticTypeWithCollection()
{
var db = DatabaseHelper.Open();
Customer actual = db.Customers.WithOrders().FindByCustomerId(1);
Assert.IsNotNull(actual);
Assert.AreEqual(1, actual.Orders.Single().OrderId);
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
}

[Test]
public void NamedParameterAndWithClauseShouldCastToStaticTypeWithCollection()
{
var db = DatabaseHelper.Open();
Customer actual = db.Customers.WithOrders().FindBy(CustomerId: 1);
Assert.IsNotNull(actual);
Assert.AreEqual(1, actual.Orders.Single().OrderId);
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
}

[Test]
public void ExpressionAndWithClauseShouldCastToStaticTypeWithCollection()
{
var db = DatabaseHelper.Open();
Customer actual = db.Customers.WithOrders().Find(db.Customers.CustomerId == 1);
Assert.IsNotNull(actual);
Assert.AreEqual(1, actual.Orders.Single().OrderId);
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
}
}
}
30 changes: 27 additions & 3 deletions Simple.Data.SqlTest/GetTests.cs
Expand Up @@ -2,6 +2,9 @@

namespace Simple.Data.SqlTest
{
using System;
using System.Linq;

[TestFixture]
public class GetTests
{
Expand All @@ -14,9 +17,30 @@ public void Setup()
[Test]
public void TestGet()
{
var db = DatabaseHelper.Open();
var user = db.Users.Get(1);
Assert.AreEqual(1, user.Id);
var db = DatabaseHelper.Open();
var user = db.Users.Get(1);
Assert.AreEqual(1, user.Id);
}

[Test]
public void WithClauseShouldCastToStaticTypeWithComplexProperty()
{
var db = DatabaseHelper.Open();
Order actual = db.Orders.WithCustomer().Get(1);
Assert.IsNotNull(actual);
Assert.IsNotNull(actual.Customer);
Assert.AreEqual("Test", actual.Customer.Name);
Assert.AreEqual("100 Road", actual.Customer.Address);
}

[Test]
public void WithClauseShouldCastToStaticTypeWithCollection()
{
var db = DatabaseHelper.Open();
Customer actual = db.Customers.WithOrders().Get(1);
Assert.IsNotNull(actual);
Assert.AreEqual(1, actual.Orders.Single().OrderId);
Assert.AreEqual(new DateTime(2010, 10, 10), actual.Orders.Single().OrderDate);
}
}
}

0 comments on commit 3c124f0

Please sign in to comment.