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

Commit dcd80f0

Browse files
authored
Merge pull request #522 from bryancrosby/master
Added table hints to Sql Server join expressions
2 parents f075192 + a1f2b72 commit dcd80f0

File tree

7 files changed

+175
-6
lines changed

7 files changed

+175
-6
lines changed

src/ServiceStack.OrmLite.SqlServer/ServiceStack.OrmLite.SqlServer.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@
103103
<Compile Include="SqlServerDialect.cs" />
104104
<Compile Include="SqlServerExpression.cs" />
105105
<Compile Include="Properties\AssemblyInfo.cs" />
106+
<Compile Include="SqlServerExpressionExtensions.cs" />
106107
<Compile Include="SqlServerOrmLiteDialectProvider.cs" />
108+
<Compile Include="SqlServerTableHint.cs" />
107109
</ItemGroup>
108110
<ItemGroup>
109111
<ProjectReference Include="..\ServiceStack.OrmLite\ServiceStack.OrmLite.csproj">

src/ServiceStack.OrmLite.SqlServer/SqlServerExpression.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Data;
3+
using System.Linq.Expressions;
34
using System.Text;
45
using ServiceStack.OrmLite.SqlServer.Converters;
56
using ServiceStack.Text;
@@ -28,6 +29,33 @@ public override SqlExpression<T> OrderByRandom()
2829
return base.OrderBy("NEWID()");
2930
}
3031

32+
public SqlExpression<T> JoinWithHint<Target>(Expression<Func<T, Target, bool>> joinExpr, string joinTableHint)
33+
{
34+
if (joinTableHint == null)
35+
{
36+
throw new ArgumentNullException("joinTableHint");
37+
}
38+
return InternalJoin("INNER JOIN", joinExpr, joinTableHint);
39+
}
40+
41+
public SqlExpression<T> LeftJoinWithHint<Target>(Expression<Func<T, Target, bool>> joinExpr, string joinTableHint)
42+
{
43+
if (joinTableHint == null)
44+
{
45+
throw new ArgumentNullException("joinTableHint");
46+
}
47+
return InternalJoin("LEFT JOIN", joinExpr, joinTableHint);
48+
}
49+
50+
public SqlExpression<T> RightJoinWithHint<Target>(Expression<Func<T, Target, bool>> joinExpr, string joinTableHint)
51+
{
52+
if (joinTableHint == null)
53+
{
54+
throw new ArgumentNullException("joinTableHint");
55+
}
56+
return InternalJoin("RIGHT JOIN", joinExpr, joinTableHint);
57+
}
58+
3159
protected override void ConvertToPlaceholderAndParameter(ref object right)
3260
{
3361
var paramName = Params.Count.ToString();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Text;
6+
using ServiceStack.DataAnnotations;
7+
8+
namespace ServiceStack.OrmLite.SqlServer
9+
{
10+
public static class SqlServerExpressionExtensions
11+
{
12+
public static SqlExpression<T> JoinWithHint<T, Target>(this SqlExpression<T> expression, Expression<Func<T, Target, bool>> joinExpr, string sqlServerTableHint)
13+
{
14+
var sqlExpression = new SqlServerExpression<T>(expression.DialectProvider);
15+
16+
return sqlExpression.JoinWithHint(joinExpr, sqlServerTableHint);
17+
}
18+
19+
public static SqlExpression<T> LeftJoinWithHint<T, Target>(this SqlExpression<T> expression, Expression<Func<T, Target, bool>> joinExpr, string sqlServerTableHint)
20+
{
21+
var sqlExpression = new SqlServerExpression<T>(expression.DialectProvider);
22+
23+
return sqlExpression.LeftJoinWithHint(joinExpr, sqlServerTableHint);
24+
25+
}
26+
27+
public static SqlExpression<T> RightJoinWithHint<T, Target>(this SqlExpression<T> expression, Expression<Func<T, Target, bool>> joinExpr, string sqlServerTableHint)
28+
{
29+
var sqlExpression = new SqlServerExpression<T>(expression.DialectProvider);
30+
31+
return sqlExpression.RightJoinWithHint(joinExpr, sqlServerTableHint);
32+
33+
}
34+
}
35+
}
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+
using ServiceStack.DataAnnotations;
6+
7+
namespace ServiceStack.OrmLite.SqlServer
8+
{
9+
public class SqlServerTableHint
10+
{
11+
public const string ReadUncommitted = "WITH (READUNCOMMITTED)";
12+
public const string ReadCommitted = "WITH (READCOMMITTED)";
13+
public const string ReadPast = "WITH (READPAST)";
14+
public const string Serializable = "WITH (SERIALIZABLE)";
15+
public const string RepeatableRead = "WITH (REPEATABLEREAD)";
16+
}
17+
}

src/ServiceStack.OrmLite.SqlServerTests/ServiceStack.OrmLite.SqlServerTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
<Compile Include="UpdateTests.cs" />
120120
<Compile Include="UseCase\ComplexJoinWithLimitAndNoOrderByTests.cs" />
121121
<Compile Include="UseCase\ComplexJoinWithLimitAndSpacesInAliasesTests.cs" />
122+
<Compile Include="UseCase\JoinWithHintUseCase.cs" />
122123
<Compile Include="UseCase\TestEntityWithAliases.cs" />
123124
<Compile Include="UseCase\SimpleUseCase.cs" />
124125
<Compile Include="UseCase\TestEntity.cs" />
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using NUnit.Framework;
8+
using ServiceStack.DataAnnotations;
9+
using ServiceStack.OrmLite.SqlServer;
10+
11+
namespace ServiceStack.OrmLite.SqlServerTests.UseCase
12+
{
13+
[TestFixture]
14+
public class JoinWithHintUseCase : OrmLiteTestBase
15+
{
16+
[Alias("car")]
17+
class Car
18+
{
19+
20+
[PrimaryKey]
21+
[Alias("car_id")]
22+
[AutoIncrement]
23+
public int CarId { get; set; }
24+
25+
[Alias("car_name")]
26+
public string Name { get; set; }
27+
}
28+
29+
[Alias("car_type")]
30+
class CarType
31+
{
32+
[Alias("car_id")]
33+
public int CarId { get; set; }
34+
35+
[Alias("car_type_name")]
36+
public string CarTypeName { get; set; }
37+
}
38+
39+
class CarTypeJoin
40+
{
41+
public int CarId { get; set; }
42+
public string CarTypeName { get; set; }
43+
}
44+
45+
private static void InitTables(IDbConnection db)
46+
{
47+
db.DropTable<Car>();
48+
db.DropTable<CarType>();
49+
50+
db.CreateTable<Car>();
51+
db.CreateTable<CarType>();
52+
53+
54+
var id1 = db.Insert(new Car { Name = "Subaru" }, true);
55+
var id2 = db.Insert(new Car { Name = "BMW" }, true);
56+
var id3 = db.Insert(new Car { Name = "Nissan" }, true);
57+
58+
db.Insert(new CarType { CarId = (int)id1, CarTypeName = "Sedan" });
59+
db.Insert(new CarType { CarId = (int)id2, CarTypeName = "Coupe" });
60+
db.Insert(new CarType { CarId = (int)id3, CarTypeName = "SUV" });
61+
}
62+
63+
[Test]
64+
public void can_join_with_readuncommitted()
65+
{
66+
using (var db = OpenDbConnection())
67+
{
68+
InitTables(db);
69+
70+
var join = db.From<Car>()
71+
.JoinWithHint<Car, CarType>((l, r) => l.CarId == r.CarId, SqlServerTableHint.ReadUncommitted);
72+
73+
var selectStatement = join.ToSelectStatement();
74+
75+
var data = db.Select<CarTypeJoin>(join);
76+
77+
Assert.That(selectStatement.Contains("READUNCOMMITTED"));
78+
}
79+
}
80+
}
81+
}

src/ServiceStack.OrmLite/Expressions/SqlExpression.Join.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,12 @@ public SqlExpression<T> CrossJoin<Source, Target>(Expression<Func<Source, Target
7676
return InternalJoin("CROSS JOIN", joinExpr);
7777
}
7878

79-
private SqlExpression<T> InternalJoin<Source, Target>(string joinType,
80-
Expression<Func<Source, Target, bool>> joinExpr)
79+
protected SqlExpression<T> InternalJoin<Source, Target>(string joinType, Expression<Func<Source, Target, bool>> joinExpr, string customJoinModifier = null)
8180
{
8281
var sourceDef = typeof(Source).GetModelDefinition();
8382
var targetDef = typeof(Target).GetModelDefinition();
8483

85-
return InternalJoin(joinType, joinExpr, sourceDef, targetDef);
84+
return InternalJoin(joinType, joinExpr, sourceDef, targetDef, customJoinModifier);
8685
}
8786

8887
private string InternalCreateSqlFromExpression(Expression joinExpr, bool isCrossJoin)
@@ -126,8 +125,7 @@ public SqlExpression<T> CustomJoin(string joinString)
126125
return this;
127126
}
128127

129-
private SqlExpression<T> InternalJoin(string joinType,
130-
Expression joinExpr, ModelDefinition sourceDef, ModelDefinition targetDef)
128+
private SqlExpression<T> InternalJoin(string joinType, Expression joinExpr, ModelDefinition sourceDef, ModelDefinition targetDef, string customJoinModifier = null)
131129
{
132130
PrefixFieldWithTableName = true;
133131

@@ -150,7 +148,14 @@ private SqlExpression<T> InternalJoin(string joinType,
150148
? sourceDef
151149
: targetDef;
152150

153-
FromExpression += " {0} {1} {2}".Fmt(joinType, SqlTable(joinDef), sqlExpr);
151+
if (customJoinModifier != null)
152+
{
153+
FromExpression += " {0} {1} {2} {3}".Fmt(joinType, SqlTable(joinDef), customJoinModifier, sqlExpr);
154+
}
155+
else
156+
{
157+
FromExpression += " {0} {1} {2}".Fmt(joinType, SqlTable(joinDef), sqlExpr);
158+
}
154159

155160
return this;
156161
}

0 commit comments

Comments
 (0)