Skip to content

Commit 19d2602

Browse files
committed
Added CommandOptimizer for super-performance awesomeness
1 parent 49bcf14 commit 19d2602

File tree

12 files changed

+137
-13
lines changed

12 files changed

+137
-13
lines changed

Simple.Data.Ado/AdoAdapter.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@ namespace Simple.Data.Ado
1616
[Export("Ado", typeof(Adapter))]
1717
public partial class AdoAdapter : Adapter, IAdapterWithRelation, IAdapterWithTransactions
1818
{
19+
private CommandOptimizer _commandOptimizer = new CommandOptimizer();
1920
private readonly AdoAdapterFinder _finder;
2021
private readonly ProviderHelper _providerHelper = new ProviderHelper();
2122

23+
public CommandOptimizer CommandOptimizer
24+
{
25+
get { return _commandOptimizer; }
26+
}
27+
2228
public ProviderHelper ProviderHelper
2329
{
2430
get { return _providerHelper; }
@@ -44,6 +50,8 @@ internal AdoAdapter(IConnectionProvider connectionProvider) : this()
4450
_connectionProvider = connectionProvider;
4551
_schema = DatabaseSchema.Get(_connectionProvider, _providerHelper);
4652
_relatedFinder = new Lazy<AdoAdapterRelatedFinder>(CreateRelatedFinder);
53+
_commandOptimizer = ProviderHelper.GetCustomProvider<CommandOptimizer>(_connectionProvider) ??
54+
new CommandOptimizer();
4755
}
4856

4957
protected override void OnSetup()
@@ -71,6 +79,8 @@ protected override void OnSetup()
7179
}
7280
_schema = DatabaseSchema.Get(_connectionProvider, _providerHelper);
7381
_relatedFinder = new Lazy<AdoAdapterRelatedFinder>(CreateRelatedFinder);
82+
_commandOptimizer = ProviderHelper.GetCustomProvider<CommandOptimizer>(_connectionProvider) ??
83+
new CommandOptimizer();
7484
}
7585

7686
private AdoAdapterRelatedFinder CreateRelatedFinder()

Simple.Data.Ado/AdoAdapterFinder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public Func<object[],IDictionary<string,object>> CreateFindOneDelegate(string ta
5454
.GetFindByCommand(_adapter.GetSchema().BuildObjectName(tableName), criteria);
5555

5656
var command = commandBuilder.GetCommand(_adapter.CreateConnection());
57+
command = _adapter.CommandOptimizer.OptimizeFindOne(command);
5758

5859
var commandTemplate =
5960
commandBuilder.GetCommandTemplate(

Simple.Data.Ado/ISqlOptimizer.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Simple.Data.Ado
7+
{
8+
using System.Data;
9+
10+
public class CommandOptimizer
11+
{
12+
public virtual IDbCommand OptimizeFindOne(IDbCommand command)
13+
{
14+
return command;
15+
}
16+
}
17+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<Compile Include="IObservableQueryRunner.cs" />
9090
<Compile Include="IQueryPager.cs" />
9191
<Compile Include="ISchemaGetter.cs" />
92+
<Compile Include="ISqlOptimizer.cs" />
9293
<Compile Include="Joiner.cs" />
9394
<Compile Include="JoinType.cs" />
9495
<Compile Include="OptimizedDictionary.cs" />

Simple.Data.Ado/TraceHelper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public static class TraceHelper
1515
public static void WriteTrace(this IDbCommand command)
1616
{
1717
// if (Trace.Listeners.Count == 0) return;
18+
if (Database.TraceLevel < TraceLevel.Info) return;
1819
try
1920
{
2021
var str = new StringBuilder();

Simple.Data.InMemoryTest/InMemoryTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,42 @@ public void SeparateThreadsShouldSeeDifferentMocks()
249249
Assert.AreEqual(2, r2);
250250
}
251251

252+
[Test]
253+
public void find_all_when_using_Name_property_should_work()
254+
{
255+
var adapter = new InMemoryAdapter();
256+
adapter.ConfigureJoin("Users", "Id", "Categories", "Categories", "UserId", "User");
257+
Database.UseMockAdapter(adapter);
258+
var db = Database.Open();
259+
260+
db.Users.Insert(Id: 1, Name: "Marcus");
261+
db.Users.Insert(Id: 2, Name: "Per");
262+
db.Categories.Insert(Id: 1, UserId: 1, Name: "Category 1");
263+
db.Categories.Insert(Id: 2, UserId: 2, Name: "Category 2");
264+
265+
var categories = db.Users.FindAll(db.User.Categories.Name == "Category 1").ToList();
266+
Assert.NotNull(categories);
267+
Assert.AreEqual(1, categories.Count); // FAILS - Count == 0
268+
}
269+
270+
[Test]
271+
public void find_all_when_using_CategoryName_property_should_work()
272+
{
273+
var adapter = new InMemoryAdapter();
274+
adapter.ConfigureJoin("Users", "Id", "Categories", "Categories", "UserId", "User");
275+
Database.UseMockAdapter(adapter);
276+
var db = Database.Open();
277+
278+
db.Users.Insert(Id: 1, UserName: "Marcus");
279+
db.Users.Insert(Id: 2, UserName: "Per");
280+
db.Categories.Insert(Id: 1, UserId: 1, CategoryName: "Category 1");
281+
db.Categories.Insert(Id: 2, UserId: 2, CategoryName: "Category 2");
282+
283+
var categories = db.Users.FindAll(db.User.Categories.CategoryName == "Category 1").ToList();
284+
Assert.NotNull(categories);
285+
Assert.AreEqual(1, categories.Count); // Works find - Count == 1
286+
}
287+
252288
private static int ThreadTestHelper(int userId)
253289
{
254290
var mockAdapter = new InMemoryAdapter();

Simple.Data.SqlServer/Simple.Data.SqlServer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
</Compile>
5454
<Compile Include="SqlCeDbParameterFactory.cs" />
5555
<Compile Include="SqlColumn.cs" />
56+
<Compile Include="SqlCommandOptimizer.cs" />
5657
<Compile Include="SqlConnectionProvider.cs" />
5758
<Compile Include="SqlObservableQueryRunner.cs" />
5859
<Compile Include="SqlQueryPager.cs" />
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Simple.Data.SqlServer
7+
{
8+
using System.ComponentModel.Composition;
9+
using System.Text.RegularExpressions;
10+
using Ado;
11+
12+
[Export(typeof(CommandOptimizer))]
13+
public class SqlCommandOptimizer : CommandOptimizer
14+
{
15+
public override System.Data.IDbCommand OptimizeFindOne(System.Data.IDbCommand command)
16+
{
17+
command.CommandText = Regex.Replace(command.CommandText, "^SELECT ", "SET NOCOUNT ON; SELECT TOP 1 ",
18+
RegexOptions.IgnoreCase);
19+
return command;
20+
}
21+
}
22+
}

Simple.Data/Database.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,28 @@
77

88
namespace Simple.Data
99
{
10+
using System.Configuration;
11+
using System.Diagnostics;
12+
1013
/// <summary>
1114
/// The entry class for Simple.Data. Provides static methods for opening databases,
1215
/// and implements runtime dynamic functionality for resolving database-level objects.
1316
/// </summary>
1417
public partial class Database : DataStrategy
1518
{
19+
private static readonly SimpleDataConfigurationSection Configuration;
20+
1621
private static readonly IDatabaseOpener DatabaseOpener;
1722
private static IPluralizer _pluralizer;
1823
private readonly Adapter _adapter;
1924

2025
static Database()
2126
{
2227
DatabaseOpener = new DatabaseOpener();
28+
Configuration =
29+
(SimpleDataConfigurationSection) ConfigurationManager.GetSection("simpleData/simpleDataConfiguration")
30+
?? new SimpleDataConfigurationSection();
31+
TraceLevel = Configuration.TraceLevel;
2332
}
2433

2534
/// <summary>
@@ -177,5 +186,12 @@ public static void UseMockAdapter(Func<Adapter> mockAdapterCreator)
177186
{
178187
Data.DatabaseOpener.UseMockAdapter(mockAdapterCreator());
179188
}
189+
190+
private static TraceLevel? _traceLevel;
191+
public static TraceLevel? TraceLevel
192+
{
193+
get { return _traceLevel ?? Configuration.TraceLevel; }
194+
set { _traceLevel = value; }
195+
}
180196
}
181197
}

Simple.Data/QueryPolyfills/WhereClauseHandler.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public WhereClauseHandler(WhereClause whereClause)
3232

3333
private Func<IDictionary<string, object>, bool> FunctionExpressionToWhereClause(SimpleExpression arg)
3434
{
35-
var key = GetKeyFromLeftOperand(arg);
3635
var function = arg.RightOperand as SimpleFunction;
3736
if (ReferenceEquals(function, null)) throw new InvalidOperationException("Expression type of function but no function supplied.");
3837
if (function.Name.Equals("like", StringComparison.OrdinalIgnoreCase))
@@ -95,16 +94,6 @@ private Func<IDictionary<string, object>, bool> EqualExpressionToWhereClause(Sim
9594
return d => Resolve(d, arg.LeftOperand).Contains(arg.RightOperand);
9695
}
9796

98-
private static string GetKeyFromLeftOperand(SimpleExpression arg)
99-
{
100-
var reference = arg.LeftOperand as ObjectReference;
101-
102-
if (reference.IsNull()) throw new NotSupportedException("Only ObjectReference types are supported.");
103-
104-
var key = reference.GetName();
105-
return key;
106-
}
107-
10897
private Func<IDictionary<string,object>, bool> Format(SimpleExpression expression)
10998
{
11099
Func<SimpleExpression, Func<IDictionary<string,object>,bool>> formatter;
@@ -133,11 +122,19 @@ private IList<object> Resolve(IDictionary<string, object> dict, object operand,
133122
{
134123
var objectReference = operand as ObjectReference;
135124
if (objectReference.IsNull()) return new object[0];
125+
136126
key = key ?? objectReference.GetAliasOrName();
127+
var keys = objectReference.GetAllObjectNames();
128+
129+
if (keys.Length > 2)
130+
{
131+
return ResolveSubs(dict, objectReference.GetOwner(), key).ToList();
132+
}
133+
137134
if (dict.ContainsKey(key))
138135
return new[] {dict[key]};
139-
var subs = ResolveSubs(dict, objectReference.GetOwner(), key).ToList();
140-
return subs;
136+
137+
return new object[0];
141138
}
142139

143140
private IEnumerable<object> ResolveSubs(IDictionary<string, object> dict, ObjectReference objectReference, string key)

0 commit comments

Comments
 (0)