Skip to content

Commit c90d110

Browse files
authored
Merge pull request #32 from yv989c/feature/order-guarantees
Feature/order guarantees
2 parents 4fb79e8 + c5b242b commit c90d110

22 files changed

+686
-1211
lines changed

README.md

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,20 @@
1010

1111
> 🤔💭 TLDR; By using QueryableValues, you can incorporate in-memory collections into your EF queries with outstanding performance and flexibility.
1212
13-
This library allows you to efficiently compose an [IEnumerable<T>] in your [Entity Framework Core] queries when using the [SQL Server Database Provider]. This is accomplished by using the `AsQueryableValues` extension method available on the [DbContext] class. Everything is evaluated on the server with a single round trip, in a way that preserves the query's [execution plan], even when the values behind the [IEnumerable<T>] are changed on subsequent executions.
13+
This library allows you to efficiently compose an [IEnumerable<T>] in your [Entity Framework Core] queries when using the [SQL Server Database Provider]. You can accomplish this by using the `AsQueryableValues` extension method that's available on the [DbContext] class. The query is processed in a single round trip to the server, in a way that preserves its [execution plan], even when the values within the [IEnumerable<T>] are changed on subsequent executions.
1414

15-
The supported types for `T` are:
16-
- Simple Type: [Byte], [Int16], [Int32], [Int64], [Decimal], [Single], [Double], [DateTime], [DateTimeOffset], [Guid], [Char], and [String].
17-
- Complex Type:
18-
- Can be an anonymous type.
19-
- Can be a user-defined class or struct with read/write properties and a public constructor.
20-
- Must have one or more simple type properties, including [Boolean].
15+
**Highlights**
16+
- ✨ Enables the composition of in-memory data within your queries, utilizing both simple and complex types.
17+
- 👌 Works with all versions of SQL Server supported by [Entity Framework Core].
18+
- ⚡ Automatically uses the most efficient strategy compatible with your SQL Server instance and configuration.
19+
- ✅ Boasts over 140 tests for reliability and compatibility, giving you added confidence.
2120

2221
For a detailed explanation of the problem solved by QueryableValues, please continue reading [here][readme-background].
2322

24-
> ✅ QueryableValues boasts over 120 integration tests that are executed on every supported version of EF. These tests ensure reliability and compatibility, giving you added confidence.
25-
2623
> 💡 Still on Entity Framework 6 (non-core)? Then [QueryableValues `EF6 Edition`](https://github.com/yv989c/BlazarTech.QueryableValues.EF6) is what you need.
2724
2825
## When Should You Use It?
29-
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. In such cases, the underlying SQL query will be efficient on subsequent executions.
30-
31-
It provides a solution to the following long standing [EF Core issue](https://github.com/dotnet/efcore/issues/13617) and enables other currently unsupported scenarios; like the ability to efficiently create joins with in-memory data.
26+
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. It provides a solution to the following [EF Core issue](https://github.com/dotnet/efcore/issues/13617) and enables other currently unsupported scenarios; like the ability to efficiently create joins with in-memory data.
3227

3328
## Your Support is Appreciated!
3429
If you feel that this solution has provided you some value, please consider [buying me a ☕][BuyMeACoffee].
@@ -83,7 +78,7 @@ public class Startup
8378
}
8479
}
8580
```
86-
> 💡 Pro-tip: `UseQueryableValues` offers an optional `options` delegate for additional configurations.
81+
> 💡 `UseQueryableValues` offers an optional `options` delegate for additional configurations.
8782
8883
## How Do You Use It?
8984
The `AsQueryableValues` extension method is provided by the `BlazarTech.QueryableValues` namespace; therefore, you must add the following `using` directive to your source code file for it to appear as a method of your [DbContext] instance:
@@ -96,6 +91,9 @@ using BlazarTech.QueryableValues;
9691
Below are a few examples composing a query using the values provided by an [IEnumerable<T>].
9792

9893
### Simple Type Examples
94+
95+
> 💡 Supports [Byte], [Int16], [Int32], [Int64], [Decimal], [Single], [Double], [DateTime], [DateTimeOffset], [Guid], [Char], and [String].
96+
9997
Using the [Contains][ContainsQueryable] LINQ method:
10098

10199
```c#
@@ -155,13 +153,30 @@ var myQuery2 =
155153
};
156154
```
157155
### Complex Type Example
156+
157+
> 💡 Must be an anonymous or user-defined type with one or more simple type properties, including [Boolean].
158+
158159
```c#
159160
// Performance Tip:
160161
// If your IEnumerable<T> item type (T) has many properties, project only
161162
// the ones you need to a new variable and use it in your query.
162163
var projectedItems = items.Select(i => new { i.CategoryId, i.ColorName });
163164

164-
var myQuery =
165+
// Example #1 (LINQ method syntax)
166+
var myQuery1 = dbContext.Product
167+
.Join(
168+
dbContext.AsQueryableValues(projectedItems),
169+
p => new { p.CategoryId, p.ColorName },
170+
pi => new { pi.CategoryId, pi.ColorName },
171+
(p, pi) => new
172+
{
173+
p.ProductId,
174+
p.Description
175+
}
176+
);
177+
178+
// Example #2 (LINQ query syntax)
179+
var myQuery2 =
165180
from p in dbContext.Product
166181
join pi in dbContext.AsQueryableValues(projectedItems) on new { p.CategoryId, p.ColorName } equals new { pi.CategoryId, pi.ColorName }
167182
select new
@@ -170,10 +185,11 @@ var myQuery =
170185
p.Description
171186
};
172187
```
188+
173189
**About Complex Types**
174-
> :warning: All the data provided by this type is transmitted to the server; therefore, ensure that it only contains the properties you need for your query. Not following this recommendation will degrade the query's performance.
190+
> ⚠️ All the data provided by this type is transmitted to the server; therefore, ensure that it only contains the properties you need for your query. Not following this recommendation will degrade the query's performance.
175191
176-
> :warning: There is a limit of up to 10 properties for any given simple type (e.g. cannot have more than 10 [Int32] properties). Exceeding that limit will cause an exception and may also suggest that you should rethink your strategy.
192+
> ⚠️ There is a limit of up to 10 properties for any given simple type (e.g. cannot have more than 10 [Int32] properties). Exceeding that limit will cause an exception and may also suggest that you should rethink your strategy.
177193
178194
# Benchmarks
179195
The following [benchmarks] consist of simple EF Core queries that have a dependency on a random sequence of [Int32], [Guid], and [String] values via the `Contains` LINQ method. It shows the performance differences between not using and using QueryableValues. In practice, the benefits of using QueryableValues are more dramatic on complex EF Core queries and busy environments.
@@ -404,7 +420,7 @@ Now, focus your attention to the first query of the green section. Here you can
404420

405421
## What Makes This Work? 🤓
406422

407-
> 🎉 QueryableValues now supports JSON serialization, which improves its performance compared to using XML. By default, QueryableValues will attempt to use JSON if it is supported.
423+
> 🎉 QueryableValues now supports JSON serialization, which improves its performance compared to using XML. By default, QueryableValues will attempt to use JSON if it is supported by your SQL Server instance and database configuration.
408424
409425
QueryableValues makes use of the XML parsing capabilities in SQL Server, which are available in all the supported versions of SQL Server to date. The provided sequence of values are serialized as XML and embedded in the underlying SQL query using a native XML parameter, then it uses SQL Server's XML type methods to project the query in a way that can be mapped by [Entity Framework Core].
410426

Version.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionEFCore3>3.7.0</VersionEFCore3>
4-
<VersionEFCore5>5.7.0</VersionEFCore5>
5-
<VersionEFCore6>6.7.0</VersionEFCore6>
6-
<VersionEFCore7>7.2.0</VersionEFCore7>
3+
<VersionEFCore3>3.8.0</VersionEFCore3>
4+
<VersionEFCore5>5.8.0</VersionEFCore5>
5+
<VersionEFCore6>6.8.0</VersionEFCore6>
6+
<VersionEFCore7>7.3.0</VersionEFCore7>
77
</PropertyGroup>
88
</Project>

docs/README.md

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,20 @@
66

77
> 🤔💭 TLDR; By using QueryableValues, you can incorporate in-memory collections into your EF queries with outstanding performance and flexibility.
88
9-
This library allows you to efficiently compose an [IEnumerable&lt;T&gt;] in your [Entity Framework Core] queries when using the [SQL Server Database Provider]. This is accomplished by using the `AsQueryableValues` extension method available on the [DbContext] class. Everything is evaluated on the server with a single round trip, in a way that preserves the query's [execution plan], even when the values behind the [IEnumerable&lt;T&gt;] are changed on subsequent executions.
9+
This library allows you to efficiently compose an [IEnumerable&lt;T&gt;] in your [Entity Framework Core] queries when using the [SQL Server Database Provider]. You can accomplish this by using the `AsQueryableValues` extension method that's available on the [DbContext] class. The query is processed in a single round trip to the server, in a way that preserves its [execution plan], even when the values within the [IEnumerable&lt;T&gt;] are changed on subsequent executions.
1010

11-
The supported types for `T` are:
12-
- Simple Type: [Byte], [Int16], [Int32], [Int64], [Decimal], [Single], [Double], [DateTime], [DateTimeOffset], [Guid], [Char], and [String].
13-
- Complex Type:
14-
- Can be an anonymous type.
15-
- Can be a user-defined class or struct with read/write properties and a public constructor.
16-
- Must have one or more simple type properties, including [Boolean].
11+
**Highlights**
12+
- ✨ Enables the composition of in-memory data within your queries, utilizing both simple and complex types.
13+
- 👌 Works with all versions of SQL Server supported by [Entity Framework Core].
14+
- ⚡ Automatically uses the most efficient strategy compatible with your SQL Server instance and configuration.
15+
- ✅ Boasts over 140 tests for reliability and compatibility, giving you added confidence.
1716

1817
For a detailed explanation of the problem solved by QueryableValues, please continue reading [here][readme-background].
1918

20-
> ✅ QueryableValues boasts over 120 integration tests that are executed on every supported version of EF. These tests ensure reliability and compatibility, giving you added confidence.
21-
2219
> 💡 Still on Entity Framework 6 (non-core)? Then [QueryableValues `EF6 Edition`](https://github.com/yv989c/BlazarTech.QueryableValues.EF6) is what you need.
2320
2421
## When Should You Use It?
25-
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. In such cases, the underlying SQL query will be efficient on subsequent executions.
26-
27-
It provides a solution to the following long standing [EF Core issue](https://github.com/dotnet/efcore/issues/13617) and enables other currently unsupported scenarios; like the ability to efficiently create joins with in-memory data.
22+
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. It provides a solution to the following [EF Core issue](https://github.com/dotnet/efcore/issues/13617) and enables other currently unsupported scenarios; like the ability to efficiently create joins with in-memory data.
2823

2924
## Your Support is Appreciated!
3025
If you feel that this solution has provided you some value, please consider [buying me a ☕][BuyMeACoffee].
@@ -79,7 +74,7 @@ public class Startup
7974
}
8075
}
8176
```
82-
> 💡 Pro-tip: `UseQueryableValues` offers an optional `options` delegate for additional configurations.
77+
> 💡 `UseQueryableValues` offers an optional `options` delegate for additional configurations.
8378
8479
## How Do You Use It?
8580
The `AsQueryableValues` extension method is provided by the `BlazarTech.QueryableValues` namespace; therefore, you must add the following `using` directive to your source code file for it to appear as a method of your [DbContext] instance:
@@ -92,6 +87,9 @@ using BlazarTech.QueryableValues;
9287
Below are a few examples composing a query using the values provided by an [IEnumerable&lt;T&gt;].
9388

9489
### Simple Type Examples
90+
91+
> 💡 Supports [Byte], [Int16], [Int32], [Int64], [Decimal], [Single], [Double], [DateTime], [DateTimeOffset], [Guid], [Char], and [String].
92+
9593
Using the [Contains][ContainsQueryable] LINQ method:
9694

9795
```c#
@@ -151,13 +149,30 @@ var myQuery2 =
151149
};
152150
```
153151
### Complex Type Example
152+
153+
> 💡 Must be an anonymous or user-defined type with one or more simple type properties, including [Boolean].
154+
154155
```c#
155156
// Performance Tip:
156157
// If your IEnumerable<T> item type (T) has many properties, project only
157158
// the ones you need to a new variable and use it in your query.
158159
var projectedItems = items.Select(i => new { i.CategoryId, i.ColorName });
159160

160-
var myQuery =
161+
// Example #1 (LINQ method syntax)
162+
var myQuery1 = dbContext.Product
163+
.Join(
164+
dbContext.AsQueryableValues(projectedItems),
165+
p => new { p.CategoryId, p.ColorName },
166+
pi => new { pi.CategoryId, pi.ColorName },
167+
(p, pi) => new
168+
{
169+
p.ProductId,
170+
p.Description
171+
}
172+
);
173+
174+
// Example #2 (LINQ query syntax)
175+
var myQuery2 =
161176
from p in dbContext.Product
162177
join pi in dbContext.AsQueryableValues(projectedItems) on new { p.CategoryId, p.ColorName } equals new { pi.CategoryId, pi.ColorName }
163178
select new
@@ -166,10 +181,11 @@ var myQuery =
166181
p.Description
167182
};
168183
```
184+
169185
**About Complex Types**
170-
> :warning: All the data provided by this type is transmitted to the server; therefore, ensure that it only contains the properties you need for your query. Not following this recommendation will degrade the query's performance.
186+
> ⚠️ All the data provided by this type is transmitted to the server; therefore, ensure that it only contains the properties you need for your query. Not following this recommendation will degrade the query's performance.
171187
172-
> :warning: There is a limit of up to 10 properties for any given simple type (e.g. cannot have more than 10 [Int32] properties). Exceeding that limit will cause an exception and may also suggest that you should rethink your strategy.
188+
> ⚠️ There is a limit of up to 10 properties for any given simple type (e.g. cannot have more than 10 [Int32] properties). Exceeding that limit will cause an exception and may also suggest that you should rethink your strategy.
173189
174190
## Do You Want To Know More? 📚
175191
Please take a look at the [repository][Repository].

src/QueryableValues.SqlServer.EFCore7/QueryableValues.SqlServer.EFCore7.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="[7.0,8.0)" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="[7.0,)" />
1414
</ItemGroup>
1515
</Project>

0 commit comments

Comments
 (0)