Kapusons.Select
1.2.0
dotnet add package Kapusons.Select --version 1.2.0
NuGet\Install-Package Kapusons.Select -Version 1.2.0
<PackageReference Include="Kapusons.Select" Version="1.2.0" />
paket add Kapusons.Select --version 1.2.0
#r "nuget: Kapusons.Select, 1.2.0"
// Install Kapusons.Select as a Cake Addin #addin nuget:?package=Kapusons.Select&version=1.2.0 // Install Kapusons.Select as a Cake Tool #tool nuget:?package=Kapusons.Select&version=1.2.0
select-options (aka ks-select)
Augments LINQ IQueryable
Select
capabilities with configurable options to allow build composable projections, based on conditional constructs.
works virtually with any LINQ provider and LINQ-based framework (LINQ to objects, ef6, ef-core, etc.), because it simply generates an expression tree for the
IQueryable
Select
method.
query.Select<Product, ProductInfo>(options =>
{
options.Include(it => it.Category, it => categoryQuery.Where(c => c.Id == it.CategoryId).Select(c => c.Name).FirstOrDefault());
options.Exclude(it => it.Description);
});
Features
Conditionally exclude or include columns
if (excludeBinaryData) query = query.Select(options => { options.Exclude(it => it.BinaryData); });
if (includeOrderCount) query = query.Select(options => { options.Include(it.OrderCount, it => orderQuery.Count(o => o.ProductId == it.Id)) });
or
query = query.Select(options =>
{
if (excludeBinaryData) options.Exclude(it => it.BinaryData);
if (includeOrderCount) options.Include(it.OrderCount, it => orderQuery.Count(o => o.ProductId == it.Id));
});
The extra columns can be applied either to the original entity (usually those columns are not mapped to the data store and are marked with the
[NotMapped]
attribute) or to a distinct type (see the demo project for an example)
AutoMapper-like projection
Properties with a matching name are automatically mapped from the original type to the target type. Supports complex type properties.
Provider agnostic
Works virtually with any LINQ provider and LINQ-based framework (LINQ to objects, ef6, ef-core, etc.), because it simply generates an expression tree for the IQueryable
Select
method.
Scoping and Chaining
The target projection can be obtained through (multiple, chained) internal query transformations without changing the type of the original IQueryable<T>
:
protected IQueryable<Book> ApplyFilter(IQueryable<Book> query, BookFilter parameters, SelectOptionsContext<Book> filterContext)
{
if (parameters.IncludeAuthorName)
{
var options = filterContext.UseSelectOptions();
var authorsQuery = Context.GetAuthorsQuery();
options.Include(it => it.AuthorName, it =>
authorsQuery.Where(g => g.Id == it.AuthorId)
.Select(it => it.FirstName + " " + it.LastName)
.FirstOrDefault());
}
if (parameters.IncludeAuthorInfo)
{
filterContext.UseScoped<BookAuthorJoin>((options, q0) =>
{
var joinedQuery = q0.Join(Context.GetAuthorsQuery(),
b => b.AuthorId,
a => a.Id,
(b, a) => new BookAuthorJoin { Book = b, Author = a });
options.Include(book => book.AuthorInfo, it => new AuthorInfo
{
FirstName = it.Author.FirstName,
LastName = it.Author.LastName,
BookSells = Context.GetBooksQuery().Count(x => x.AuthorId == it.Author.Id),
});
return joinedQuery;
}, it => it.Book);
}
// replace Title and Description fields with localized versions from BooksLocalization (demonstrated in the sample project)
if (CultureInfo.CurrentUICulture.Name != DefaultLanguage)
{
filterContext.UseScoped<BookLocalizationJoin>((options, q0) =>
{
var joinedQuery = q0.Join(Context.GetBooksLocalizationQuery(),
b => b.Id,
l => l.BookId,
(b, l) => new BookLocalizationJoin { Book = b, Localization = l });
options.Include(book => book.Title, it => it.Localization.Title);
options.Include(book => book.Description, it => it.Localization.Description);
return joinedQuery;
}, it => it.Book);
}
// ...
query = query.ApplySelectOptions(filterContext);
return query;
}
No collisions/ambiguities with standard Queryable Select methods
The different query overloads can be both used in the same context without explicit casts/type parameters, because the compiler (and Visual Studio Intellisense) is smart enough to pick automatically the right method:
// standard Queryable methods
query.Select(it => it.Name);
query.Select(it => new { it.Name });
// select-options method
query.Select(o => o.Include(it => it.RelatedItemCount, it => relatedItemQuery.Count()));
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.ComponentModel.Annotations (>= 5.0.0)
-
.NETStandard 2.1
- System.ComponentModel.Annotations (>= 5.0.0)
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.