The documentation comes from the Markdown files in the source code, so is always up-to-date but available only in English. Enjoy!
LINQ provides a unified model for querying both in-memory objects and databases. However, the standard LINQ join syntax can be cumbersome, especially for common SQL join scenarios. The Signum Framework offers a more SQL-like approach for joins, making queries simpler and more intuitive.
In standard LINQ, there are two main join operators:
// Joins two sequences based on matching keys and projects the result.
public static IQueryable<TResult> Join<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IEnumerable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TOuter, TInner, TResult>> resultSelector)
// Groups the results of two sequences based on matching keys.
public static IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IEnumerable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector)There is no explicit OUTER JOIN operator. Instead, you achieve a LEFT OUTER JOIN by combining GroupJoin, SelectMany, and DefaultIfEmpty:
using (var db = new BugContext())
{
var q = from b in db.Bugs
join c in db.Comments on b.Id equals c.BugId into g
from c in g.DefaultIfEmpty()
select new { b.Description, CommentText = c == null ? "(no comment)" : c.Text };
}Limitations:
LEFT OUTER JOIN.RIGHT OUTER JOIN or FULL OUTER JOIN.Signum Framework provides a more SQL-like join syntax. You can use DefaultIfEmpty() on either side of the join to specify which side should allow nulls (i.e., which side is 'outer'). This enables LEFT, RIGHT, and FULL OUTER JOIN scenarios directly.
Example:
var q = from b in Database.Query<BugEntity>()
join c in Database.Query<CommentEntity>().DefaultIfEmpty() on b equals c.Bug
select new { b.Description, CommentText = c == null ? "(no comment)" : c.Text };Explicit joins are typically used when joining on non-foreign-key fields. For foreign keys, implicit joins are usually more convenient in Signum.
Suppose you want to join pairs of consecutive bugs by Start and End date:
Returns only matched pairs:
from b1 in Database.Query<BugEntity>()
join b2 in Database.Query<BugEntity>() on b1.End equals b2.Start
select new { b1, b2 }Returns all b1 bugs, with b2 as the next bug or null:
from b1 in Database.Query<BugEntity>()
join b2 in Database.Query<BugEntity>().DefaultIfEmpty() on b1.End equals b2.Start
select new { b1, b2 }Returns all b2 bugs, with b1 as the previous bug or null:
from b1 in Database.Query<BugEntity>().DefaultIfEmpty()
join b2 in Database.Query<BugEntity>() on b1.End equals b2.Start
select new { b1, b2 }Returns all bugs from both sides, with matching pairs if they exist, or null if not:
from b1 in Database.Query<BugEntity>().DefaultIfEmpty()
join b2 in Database.Query<BugEntity>().DefaultIfEmpty() on b1.End equals b2.Start
select new { b1, b2 }© Signum Software. All Rights Reserved.
Powered by Signum Framework