Add typed join specification builder syntax
This commit is contained in:
@@ -7190,6 +7190,12 @@ namespace DynamORM
|
|||||||
/// <returns>Builder instance.</returns>
|
/// <returns>Builder instance.</returns>
|
||||||
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner);
|
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner);
|
||||||
|
|
||||||
|
/// <summary>Add typed join using join-spec builder syntax (<c>As()</c>, join kind and <c>On()</c>).</summary>
|
||||||
|
/// <typeparam name="TRight">Joined mapped entity type.</typeparam>
|
||||||
|
/// <param name="specification">Join specification builder callback.</param>
|
||||||
|
/// <returns>Builder instance.</returns>
|
||||||
|
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Func<TypedJoinBuilder<T, TRight>, TypedJoinBuilder<T, TRight>> specification);
|
||||||
|
|
||||||
/// <summary>Add INNER JOIN using typed ON predicate.</summary>
|
/// <summary>Add INNER JOIN using typed ON predicate.</summary>
|
||||||
IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||||
|
|
||||||
@@ -7402,6 +7408,64 @@ namespace DynamORM
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>Typed join specification builder used by typed fluent select queries.</summary>
|
||||||
|
/// <typeparam name="TLeft">Left side mapped type.</typeparam>
|
||||||
|
/// <typeparam name="TRight">Right side mapped type.</typeparam>
|
||||||
|
public class TypedJoinBuilder<TLeft, TRight>
|
||||||
|
{
|
||||||
|
internal TypedJoinBuilder()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Inner;
|
||||||
|
}
|
||||||
|
/// <summary>Gets join alias.</summary>
|
||||||
|
public string Alias { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Gets join type.</summary>
|
||||||
|
public DynamicJoinType JoinType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Gets ON predicate.</summary>
|
||||||
|
public Expression<Func<TLeft, TRight, bool>> OnPredicate { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Sets join alias.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> As(string alias)
|
||||||
|
{
|
||||||
|
Alias = alias;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>Sets INNER JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Inner()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Inner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>Sets LEFT JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Left()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Left;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>Sets RIGHT JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Right()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Right;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>Sets FULL JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Full()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Full;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>Sets ON predicate.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> On(Expression<Func<TLeft, TRight, bool>> predicate)
|
||||||
|
{
|
||||||
|
if (predicate == null)
|
||||||
|
throw new ArgumentNullException("predicate");
|
||||||
|
|
||||||
|
OnPredicate = predicate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>Compatibility and convenience extensions for typed joins.</summary>
|
/// <summary>Compatibility and convenience extensions for typed joins.</summary>
|
||||||
public static class TypedJoinExtensions
|
public static class TypedJoinExtensions
|
||||||
{
|
{
|
||||||
@@ -10742,6 +10806,19 @@ namespace DynamORM
|
|||||||
base.Join(x => joinExpr);
|
base.Join(x => joinExpr);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Func<TypedJoinBuilder<T, TRight>, TypedJoinBuilder<T, TRight>> specification)
|
||||||
|
{
|
||||||
|
if (specification == null)
|
||||||
|
throw new ArgumentNullException("specification");
|
||||||
|
|
||||||
|
TypedJoinBuilder<T, TRight> spec = specification(new TypedJoinBuilder<T, TRight>());
|
||||||
|
if (spec == null)
|
||||||
|
throw new ArgumentException("Join specification cannot resolve to null.", "specification");
|
||||||
|
if (spec.OnPredicate == null)
|
||||||
|
throw new ArgumentException("Join specification must define ON predicate.", "specification");
|
||||||
|
|
||||||
|
return Join(spec.OnPredicate, spec.Alias, spec.JoinType);
|
||||||
|
}
|
||||||
public IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
public IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||||
{
|
{
|
||||||
return Join(on, alias, DynamicJoinType.Inner);
|
return Join(on, alias, DynamicJoinType.Inner);
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace DynamORM.Tests.Select
|
|||||||
public void TestTypedJoin()
|
public void TestTypedJoin()
|
||||||
{
|
{
|
||||||
var cmd = Database.From<TypedFluentUser>("u")
|
var cmd = Database.From<TypedFluentUser>("u")
|
||||||
.Join<TypedFluentUser>((l, r) => l.Id == r.Id, "x")
|
.Join<TypedFluentUser>(j => j.As("x").On((l, r) => l.Id == r.Id))
|
||||||
.Select(u => u.Id);
|
.Select(u => u.Id);
|
||||||
|
|
||||||
Assert.AreEqual("SELECT u.\"id_user\" FROM \"sample_users\" AS u INNER JOIN \"sample_users\" AS x ON (u.\"id_user\" = x.\"id_user\")",
|
Assert.AreEqual("SELECT u.\"id_user\" FROM \"sample_users\" AS u INNER JOIN \"sample_users\" AS x ON (u.\"id_user\" = x.\"id_user\")",
|
||||||
@@ -111,7 +111,7 @@ namespace DynamORM.Tests.Select
|
|||||||
public void TestTypedLeftJoin()
|
public void TestTypedLeftJoin()
|
||||||
{
|
{
|
||||||
var cmd = Database.From<TypedFluentUser>("u")
|
var cmd = Database.From<TypedFluentUser>("u")
|
||||||
.LeftJoin<TypedFluentUser>((l, r) => l.Id == r.Id, "x")
|
.Join<TypedFluentUser>(j => j.Left().As("x").On((l, r) => l.Id == r.Id))
|
||||||
.Select(u => u.Id);
|
.Select(u => u.Id);
|
||||||
|
|
||||||
Assert.AreEqual("SELECT u.\"id_user\" FROM \"sample_users\" AS u LEFT JOIN \"sample_users\" AS x ON (u.\"id_user\" = x.\"id_user\")",
|
Assert.AreEqual("SELECT u.\"id_user\" FROM \"sample_users\" AS u LEFT JOIN \"sample_users\" AS x ON (u.\"id_user\" = x.\"id_user\")",
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ namespace DynamORM.Builders
|
|||||||
/// <returns>Builder instance.</returns>
|
/// <returns>Builder instance.</returns>
|
||||||
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner);
|
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner);
|
||||||
|
|
||||||
|
/// <summary>Add typed join using join-spec builder syntax (<c>As()</c>, join kind and <c>On()</c>).</summary>
|
||||||
|
/// <typeparam name="TRight">Joined mapped entity type.</typeparam>
|
||||||
|
/// <param name="specification">Join specification builder callback.</param>
|
||||||
|
/// <returns>Builder instance.</returns>
|
||||||
|
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Func<TypedJoinBuilder<T, TRight>, TypedJoinBuilder<T, TRight>> specification);
|
||||||
|
|
||||||
/// <summary>Add INNER JOIN using typed ON predicate.</summary>
|
/// <summary>Add INNER JOIN using typed ON predicate.</summary>
|
||||||
IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,20 @@ namespace DynamORM.Builders.Implementation
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Func<TypedJoinBuilder<T, TRight>, TypedJoinBuilder<T, TRight>> specification)
|
||||||
|
{
|
||||||
|
if (specification == null)
|
||||||
|
throw new ArgumentNullException("specification");
|
||||||
|
|
||||||
|
TypedJoinBuilder<T, TRight> spec = specification(new TypedJoinBuilder<T, TRight>());
|
||||||
|
if (spec == null)
|
||||||
|
throw new ArgumentException("Join specification cannot resolve to null.", "specification");
|
||||||
|
if (spec.OnPredicate == null)
|
||||||
|
throw new ArgumentException("Join specification must define ON predicate.", "specification");
|
||||||
|
|
||||||
|
return Join(spec.OnPredicate, spec.Alias, spec.JoinType);
|
||||||
|
}
|
||||||
|
|
||||||
public IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
public IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||||
{
|
{
|
||||||
return Join(on, alias, DynamicJoinType.Inner);
|
return Join(on, alias, DynamicJoinType.Inner);
|
||||||
|
|||||||
76
DynamORM/Builders/TypedJoinBuilder.cs
Normal file
76
DynamORM/Builders/TypedJoinBuilder.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||||
|
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace DynamORM.Builders
|
||||||
|
{
|
||||||
|
/// <summary>Typed join specification builder used by typed fluent select queries.</summary>
|
||||||
|
/// <typeparam name="TLeft">Left side mapped type.</typeparam>
|
||||||
|
/// <typeparam name="TRight">Right side mapped type.</typeparam>
|
||||||
|
public class TypedJoinBuilder<TLeft, TRight>
|
||||||
|
{
|
||||||
|
internal TypedJoinBuilder()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets join alias.</summary>
|
||||||
|
public string Alias { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Gets join type.</summary>
|
||||||
|
public DynamicJoinType JoinType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Gets ON predicate.</summary>
|
||||||
|
public Expression<Func<TLeft, TRight, bool>> OnPredicate { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Sets join alias.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> As(string alias)
|
||||||
|
{
|
||||||
|
Alias = alias;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Sets INNER JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Inner()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Inner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Sets LEFT JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Left()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Left;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Sets RIGHT JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Right()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Right;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Sets FULL JOIN.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> Full()
|
||||||
|
{
|
||||||
|
JoinType = DynamicJoinType.Full;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Sets ON predicate.</summary>
|
||||||
|
public TypedJoinBuilder<TLeft, TRight> On(Expression<Func<TLeft, TRight, bool>> predicate)
|
||||||
|
{
|
||||||
|
if (predicate == null)
|
||||||
|
throw new ArgumentNullException("predicate");
|
||||||
|
|
||||||
|
OnPredicate = predicate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user