Skip to content

Commit e67f2ed

Browse files
authored
Merge pull request #17 from yv989c/develop
Develop
2 parents 68f9359 + 4c4801b commit e67f2ed

File tree

8 files changed

+49
-37
lines changed

8 files changed

+49
-37
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88
[![GitHub Stars](https://badgen.net/github/stars/yv989c/BlazarTech.QueryableValues.EF6?icon=github)][Repository]
99
[![Nuget Downloads](https://badgen.net/nuget/dt/BlazarTech.QueryableValues.EF6.SqlServer?icon=nuget)][NuGet Package]
1010

11-
This library allows you to efficiently compose an [IEnumerable<T>] in your [Entity Framework 6] (non-core) queries when using the [SQL Server 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.
11+
> 🤔💭 TLDR; By using QueryableValues, you can incorporate in-memory collections into your EF queries with outstanding performance and flexibility.
1212
13-
The supported types for `T` are: [Byte], [Int16], [Int32], [Int64], [Guid], and [String].
13+
This library allows you to efficiently compose an [IEnumerable<T>] in your [Entity Framework 6] (non-core) queries when using the [SQL Server 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. The supported types for `T` are: [Byte], [Int16], [Int32], [Int64], [Guid], and [String].
14+
15+
**Highlights**
16+
- ✨ Enables the composition of in-memory data within your queries.
17+
- 👌 Works with all versions of SQL Server supported by [Entity Framework 6].
18+
- ⚡ Automatically uses the most efficient strategy compatible with your SQL Server instance and configuration.
19+
- ✅ Boasts over 700 tests for reliability and compatibility, giving you added confidence.
1420

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

@@ -19,7 +25,7 @@ For a detailed explanation of the problem solved by QueryableValues, please cont
1925
> 💡 Using Entity Framework Core? Then [the original version][QueryableValuesEFCoreRepository] of QueryableValues is what you need.
2026
2127
## When Should You Use It?
22-
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.
28+
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. It also enables joins with in-memory data.
2329

2430
## Your Support is Appreciated!
2531
If you feel that this solution has provided you some value, please consider [buying me a ☕][BuyMeACoffee].

Version.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>1.1.2</VersionPrefix>
3+
<VersionPrefix>1.1.3</VersionPrefix>
44
</PropertyGroup>
55
</Project>

docs/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
[![GitHub Stars](https://badgen.net/github/stars/yv989c/BlazarTech.QueryableValues.EF6?icon=github)][Repository]
55
[![Nuget Downloads](https://badgen.net/nuget/dt/BlazarTech.QueryableValues.EF6.SqlServer?icon=nuget)][NuGet Package]
66

7-
This library allows you to efficiently compose an [IEnumerable&lt;T&gt;] in your [Entity Framework 6] (non-core) queries when using the [SQL Server 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.
7+
> 🤔💭 TLDR; By using QueryableValues, you can incorporate in-memory collections into your EF queries with outstanding performance and flexibility.
88
9-
The supported types for `T` are: [Byte], [Int16], [Int32], [Int64], [Guid], and [String].
9+
This library allows you to efficiently compose an [IEnumerable&lt;T&gt;] in your [Entity Framework 6] (non-core) queries when using the [SQL Server 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. The supported types for `T` are: [Byte], [Int16], [Int32], [Int64], [Guid], and [String].
10+
11+
**Highlights**
12+
- ✨ Enables the composition of in-memory data within your queries.
13+
- 👌 Works with all versions of SQL Server supported by [Entity Framework 6].
14+
- ⚡ Automatically uses the most efficient strategy compatible with your SQL Server instance and configuration.
15+
- ✅ Boasts over 700 tests for reliability and compatibility, giving you added confidence.
1016

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

@@ -15,7 +21,7 @@ For a detailed explanation of the problem solved by QueryableValues, please cont
1521
> 💡 Using Entity Framework Core? Then [the original version][QueryableValuesEFCoreRepository] of QueryableValues is what you need.
1622
1723
## When Should You Use It?
18-
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.
24+
The `AsQueryableValues` extension method is intended for queries that are dependent upon a *non-constant* sequence of external values. It also enables joins with in-memory data.
1925

2026
## Your Support is Appreciated!
2127
If you feel that this solution has provided you some value, please consider [buying me a ☕][BuyMeACoffee].

src/QueryableValues.EF6.SqlServer/DbUtil.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Collections.Concurrent;
3-
using System.Data.SqlClient;
3+
using System.Data.Common;
44

55
namespace BlazarTech.QueryableValues
66
{
@@ -15,14 +15,14 @@ internal static class DbUtil
1515
/// <remarks>
1616
/// The result is cached on a per connection string fashion.
1717
/// </remarks>
18-
public static bool IsJsonSupported(SqlConnection connection)
18+
public static bool IsJsonSupported(DbConnection connection)
1919
{
2020
#if NET452
2121
return JsonSupportByConnectionString.GetOrAdd(connection.ConnectionString, key => isJsonSupported(key, connection));
2222
#else
2323
return JsonSupportByConnectionString.GetOrAdd(connection.ConnectionString, isJsonSupported, connection);
2424
#endif
25-
static bool isJsonSupported(string key, SqlConnection connection)
25+
static bool isJsonSupported(string key, DbConnection connection)
2626
{
2727
try
2828
{
@@ -41,7 +41,8 @@ static bool isJsonSupported(string key, SqlConnection connection)
4141
// https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql
4242
if (majorVersionNumber >= 13)
4343
{
44-
using var cm = new SqlCommand("SELECT [compatibility_level] FROM [sys].[databases] WHERE [database_id] = DB_ID()", connection);
44+
using var cm = connection.CreateCommand();
45+
cm.CommandText = "SELECT [compatibility_level] FROM [sys].[databases] WHERE [database_id] = DB_ID()";
4546
var compatibilityLevel = Convert.ToInt32(cm.ExecuteScalar());
4647
return compatibilityLevel >= 130;
4748
}

src/QueryableValues.EF6.SqlServer/QueryableValuesCommandInterceptor.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ private static void TransformCommand(DbCommand command, DbCommandInterceptionCon
9595
return;
9696
}
9797

98-
if (command.Connection is not SqlConnection)
99-
{
100-
throw Util.NewOnlyWorksWithSqlServerException();
101-
}
102-
10398
var entry = (InterceptedCommandData)Cache.Get(originalCommandText);
10499

105100
if (entry is null)
@@ -182,8 +177,15 @@ private static void TransformCommand(DbCommand command, DbCommandInterceptionCon
182177
Cache.Add(originalCommandText, entry, cachePolicy);
183178
}
184179

185-
foreach (SqlParameter parameter in command.Parameters)
180+
foreach (DbParameter parameterObj in command.Parameters)
186181
{
182+
if (parameterObj is null)
183+
{
184+
continue;
185+
}
186+
187+
var parameter = parameterObj as SqlParameter ?? throw Util.NewOnlyWorksWithSqlServerException();
188+
187189
if (entry.Parameters.TryGetValue(parameter.ParameterName, out SerializationFormat serializationFormat))
188190
{
189191
if (serializationFormat == SerializationFormat.Xml)

src/QueryableValues.EF6.SqlServer/QueryableValuesDbContextExtensions.cs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Collections.Generic;
55
using System.Data.Entity;
66
using System.Data.Entity.Infrastructure.Interception;
7-
using System.Data.SqlClient;
87
using System.Linq;
98

109
namespace BlazarTech.QueryableValues
@@ -30,16 +29,21 @@ public static class QueryableValuesDbContextExtensions
3029
var entityType = dbContextType
3130
.GetProperties()
3231
.Select(i => i.PropertyType)
33-
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(DbSet<>))
32+
.Where(i => i.IsGenericType && isDbSet(i.GetGenericTypeDefinition()))
3433
.Select(i => i.GenericTypeArguments[0])
3534
.FirstOrDefault();
3635

3736
if (entityType is null)
3837
{
39-
throw new InvalidOperationException("QueryableValues only works on a DbContext with at least one public DbSet<>.");
38+
throw new InvalidOperationException("QueryableValues only works on a DbContext with at least one public DbSet<> or IDbSet<>.");
4039
}
4140

4241
return entityType;
42+
43+
static bool isDbSet(Type type)
44+
{
45+
return type == typeof(DbSet<>) || type == typeof(IDbSet<>);
46+
}
4347
};
4448

4549
private static readonly ISerializer XmlSerializer = new XmlSerializer();
@@ -171,25 +175,18 @@ private static void ThrowIfNull(object @object, string name)
171175

172176
private static ISerializer GetSerializer(DbContext dbContext)
173177
{
174-
if (dbContext.Database.Connection is SqlConnection connection)
178+
var configuration = QueryableValuesConfigurator.GetConfiguration(dbContext.GetType());
179+
var useJson =
180+
configuration.SerializationOptions == SerializationOptions.UseJson ||
181+
(configuration.SerializationOptions == SerializationOptions.Auto && DbUtil.IsJsonSupported(dbContext.Database.Connection));
182+
183+
if (useJson)
175184
{
176-
var configuration = QueryableValuesConfigurator.GetConfiguration(dbContext.GetType());
177-
var useJson =
178-
configuration.SerializationOptions == SerializationOptions.UseJson ||
179-
(configuration.SerializationOptions == SerializationOptions.Auto && DbUtil.IsJsonSupported(connection));
180-
181-
if (useJson)
182-
{
183-
return JsonSerializer;
184-
}
185-
else
186-
{
187-
return XmlSerializer;
188-
}
185+
return JsonSerializer;
189186
}
190187
else
191188
{
192-
throw Util.NewOnlyWorksWithSqlServerException();
189+
return XmlSerializer;
193190
}
194191
}
195192

tests/QueryableValues.EF6.SqlServer.Tests.EF60/InfrastructureTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void DbSetIsRequired()
1616
_ = db.AsQueryableValues(new[] { 1 }).ToList();
1717
});
1818

19-
Assert.Contains("QueryableValues only works on a DbContext with at least one public DbSet<>.", exception.Message);
19+
Assert.Contains("QueryableValues only works on a DbContext with at least one public DbSet<> or IDbSet<>.", exception.Message);
2020
}
2121

2222
[Fact]

tests/QueryableValues.EF6.SqlServer.Tests.EF64.DotNetCore/QueryableValues.EF6.SqlServer.Tests.EF64.DotNetCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<Import Project="..\SharedTestProjectProperties.xml" />
44

55
<PropertyGroup>
6-
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
6+
<TargetFrameworks>net6.0</TargetFrameworks>
77
<RootNamespace>BlazarTech.QueryableValues.EF6.SqlServer.Tests</RootNamespace>
88
<AssemblyName>BlazarTech.QueryableValues.EF6.SqlServer.Tests.EF64</AssemblyName>
99
<Nullable>enable</Nullable>

0 commit comments

Comments
 (0)