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

Commit 7805964

Browse files
committed
Merge pull request #372 from BruceCowan-AI/FixJoinSqlBuilderUseWithOracle
Fix join sql builder use with oracle
2 parents 0af1405 + cb90f13 commit 7805964

File tree

7 files changed

+131
-12
lines changed

7 files changed

+131
-12
lines changed

src/ServiceStack.OrmLite.Oracle.Tests/ServiceStack.OrmLite.Oracle.Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
<SpecificVersion>False</SpecificVersion>
5353
<HintPath>..\..\lib\tests\nunit.framework.dll</HintPath>
5454
</Reference>
55+
<Reference Include="ServiceStack">
56+
<HintPath>..\..\lib\ServiceStack.dll</HintPath>
57+
</Reference>
5558
<Reference Include="ServiceStack.Common">
5659
<HintPath>..\..\lib\ServiceStack.Common.dll</HintPath>
5760
</Reference>
@@ -321,6 +324,9 @@
321324
<Compile Include="..\GlobalAssemblyInfo.cs">
322325
<Link>Properties\GlobalAssemblyInfo.cs</Link>
323326
</Compile>
327+
<Compile Include="WrappedCommandTests.cs">
328+
<SubType>Component</SubType>
329+
</Compile>
324330
<Compile Include="DateTimeColumnTest.cs" />
325331
<Compile Include="ForeignKeyAttributeTests.cs" />
326332
<Compile Include="OracleParamTests.cs">
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.Data;
2+
using System.Data.Common;
3+
using NUnit.Framework;
4+
using ServiceStack.MiniProfiler;
5+
using ServiceStack.MiniProfiler.Data;
6+
using ServiceStack.OrmLite.Oracle;
7+
8+
namespace ServiceStack.OrmLite.Tests
9+
{
10+
[TestFixture]
11+
public class WrappedCommandTests : OrmLiteTestBase
12+
{
13+
[Test]
14+
public void WrappingWithMiniProfilerSucceeds()
15+
{
16+
var factory = new OrmLiteConnectionFactory(ConnectionString, OracleDialect.Provider)
17+
{
18+
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
19+
};
20+
21+
using (var db = factory.OpenDbConnection())
22+
{
23+
DoInsertUpdate(db);
24+
}
25+
}
26+
27+
private static void DoInsertUpdate(IDbConnection db)
28+
{
29+
db.CreateTable<ParamPassword>(true);
30+
31+
var row = new ParamPassword { Id = 2, Password = 6 };
32+
db.Insert(row);
33+
34+
row.Password = 335;
35+
db.Update(row);
36+
}
37+
38+
[Test]
39+
public void WrappingWithSpecializedMiniProfilerSucceeds()
40+
{
41+
var factory = new OrmLiteConnectionFactory(ConnectionString, OracleDialect.Provider)
42+
{
43+
ConnectionFilter = x => new SpecializedProfiledDbConnection(x, Profiler.Current)
44+
};
45+
46+
using (var db = factory.OpenDbConnection())
47+
{
48+
DoInsertUpdate(db);
49+
}
50+
}
51+
}
52+
53+
public class ParamPassword
54+
{
55+
public int Id { get; set; }
56+
public int Password { get; set; }
57+
}
58+
59+
public class SpecializedProfiledDbConnection : ProfiledDbConnection
60+
{
61+
public SpecializedProfiledDbConnection(DbConnection connection, IDbProfiler profiler, bool autoDisposeConnection = true)
62+
: base(connection, profiler, autoDisposeConnection)
63+
{ }
64+
65+
public SpecializedProfiledDbConnection(IDbConnection connection, IDbProfiler profiler, bool autoDisposeConnection = true)
66+
: base(connection, profiler, autoDisposeConnection)
67+
{ }
68+
69+
protected override DbCommand CreateDbCommand()
70+
{
71+
return new SpecializedProfiledDbCommand(InnerConnection.CreateCommand(), InnerConnection, Profiler);
72+
}
73+
}
74+
75+
public class SpecializedProfiledDbCommand : ProfiledDbCommand
76+
{
77+
public SpecializedProfiledDbCommand(DbCommand cmd, DbConnection conn, IDbProfiler profiler)
78+
: base(cmd, conn, profiler)
79+
{ }
80+
}
81+
}
Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Data;
4+
using System.Reflection;
5+
using System.Reflection.Emit;
36

47
namespace ServiceStack.OrmLite.Oracle
58
{
@@ -9,16 +12,37 @@ public override IDbCommand CreateCommand(IDbConnection dbConn)
912
{
1013
var command = base.CreateCommand(dbConn);
1114

12-
// Doing comparison and set this way to avoid having a reference to the Oracle client
13-
// so that customers can use a different version than we used to compile without
14-
// requiring a version redirect in a config file somewhere.
15-
var commandType = command.GetType();
16-
if (commandType.FullName.StartsWith("Oracle.DataAccess.Client", StringComparison.InvariantCulture))
15+
var action = GetBindByNameSetter(command.GetType());
16+
if (action != null) action(command, true);
17+
18+
return command;
19+
}
20+
21+
private static readonly Dictionary<Type, Action<IDbCommand, bool>> Cache = new Dictionary<Type, Action<IDbCommand, bool>>();
22+
private static Action<IDbCommand, bool> GetBindByNameSetter(Type commandType)
23+
{
24+
if (commandType == null) return null;
25+
26+
Action<IDbCommand, bool> action;
27+
if (Cache.TryGetValue(commandType, out action)) return action;
28+
29+
var prop = commandType.GetProperty("BindByName", BindingFlags.Public | BindingFlags.Instance);
30+
MethodInfo setter;
31+
if (prop != null && prop.CanWrite && prop.PropertyType == typeof(bool)
32+
&& prop.GetIndexParameters().Length == 0 && (setter = prop.GetSetMethod()) != null)
1733
{
18-
var pi = commandType.GetProperty("BindByName");
19-
pi.SetValue(command, true, null);
34+
var methodName = commandType.GetOperationName() + "_BindByName";
35+
var method = new DynamicMethod(methodName, null, new []{ typeof(IDbCommand), typeof(bool) });
36+
var il = method.GetILGenerator();
37+
il.Emit(OpCodes.Ldarg_0);
38+
il.Emit(OpCodes.Castclass, commandType);
39+
il.Emit(OpCodes.Ldarg_1);
40+
il.EmitCall(OpCodes.Callvirt, setter, null);
41+
il.Emit(OpCodes.Ret);
42+
action = (Action<IDbCommand, bool>)method.CreateDelegate(typeof(Action<IDbCommand, bool>));
2043
}
21-
return command;
44+
Cache.Add(commandType, action);
45+
return action;
2246
}
2347
}
2448
}

src/ServiceStack.OrmLite.Oracle/OracleOrmLiteDialectProvider.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Linq.Expressions;
88
using System.Reflection;
99
using System.Text;
10+
using System.Text.RegularExpressions;
1011
using System.Threading;
1112

1213
namespace ServiceStack.OrmLite.Oracle
@@ -285,7 +286,8 @@ public override string ToSelectStatement(Type tableType, string sqlFilter, para
285286

286287
if (isFullSelectStatement)
287288
{
288-
if (!sqlFilter.Trim().ToUpperInvariant().Contains(" FROM ")) sqlFilter += " FROM DUAL";
289+
if (Regex.Matches(sqlFilter.Trim().ToUpperInvariant(), @"(\b|\n)FROM(\b|\n)").Count < 1)
290+
sqlFilter += " FROM DUAL";
289291
return sqlFilter.SqlFmt(filterParams);
290292
}
291293

src/ServiceStack.OrmLite.Oracle/ServiceStack.OrmLite.Oracle.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
4242
</PropertyGroup>
4343
<ItemGroup>
44+
<Reference Include="ServiceStack.Client">
45+
<HintPath>..\..\lib\ServiceStack.Client.dll</HintPath>
46+
</Reference>
4447
<Reference Include="ServiceStack.Text">
4548
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
4649
</Reference>

tests/ServiceStack.OrmLite.Tests/JoinSqlBuilderTests.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
using System.Text.RegularExpressions;
12
using NUnit.Framework;
2-
using System;
33
using ServiceStack.DataAnnotations;
44

55
namespace ServiceStack.OrmLite.Tests
@@ -82,6 +82,9 @@ public void DoubleWhereLeftJoinTest ()
8282
var expectedNq = "SELECT \"User\".Id,\"User\".Name,\"User\".Age \nFROM \"User\" \n LEFT OUTER JOIN Addresses ON \"User\".Id = Addresses.UserId \nWHERE (\"User\".Age > 18) AND (Addresses.Countryalias = 'Italy') \n";
8383

8484
Assert.That(joinQuery, Is.EqualTo(expected).Or.EqualTo(expectedNq));
85+
86+
var stmt = OrmLiteConfig.DialectProvider.ToSelectStatement(typeof(User), joinQuery);
87+
Assert.That(Regex.Matches(stmt, @"(\b|\n)FROM(\b|\n)", RegexOptions.IgnoreCase).Count, Is.EqualTo(1));
8588
}
86-
}
89+
}
8790
}

tests/ServiceStack.OrmLite.Tests/ShippersExample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void Shippers_UseCase()
120120

121121
//Performing custom queries
122122
//Select only a subset from the table
123-
var partialColumns = db.Select<SubsetOfShipper>(db.From<Shipper>().Where(q => q.ShipperTypeId == 2));
123+
var partialColumns = db.Select<SubsetOfShipper>(db.From<Shipper>().Where(q => q.ShipperTypeId == planesType.Id));
124124
Assert.That(partialColumns, Has.Count.EqualTo(2));
125125

126126
partialColumns = db.SelectFmt<SubsetOfShipper>(typeof (Shipper), "ShipperTypeId = {0}", planesType.Id);

0 commit comments

Comments
 (0)