Skip to content

Commit ee91f65

Browse files
committed
Add .NET 9 + EF 9 support
1 parent f826bb5 commit ee91f65

File tree

64 files changed

+292
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+292
-21
lines changed

Directory.Packages.props

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,28 @@
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
5+
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
6+
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
7+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" />
8+
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
9+
</ItemGroup>
10+
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
11+
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
12+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
13+
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
14+
</ItemGroup>
515
<ItemGroup>
6-
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
7-
<PackageVersion Include="BenchmarkDotNet" Version="0.13.2" />
8-
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
9-
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
10-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
11-
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
12-
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
13-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
14-
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
15-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
16+
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.7.9" />
17+
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
18+
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
19+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
20+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
21+
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
22+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
1623
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
1724
<PackageVersion Include="ScenarioTests.XUnit" Version="1.0.1" />
1825
<PackageVersion Include="Verify.Xunit" Version="22.5.0" />
19-
<PackageVersion Include="xunit" Version="2.6.2" />
20-
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
26+
<PackageVersion Include="xunit" Version="2.9.2" />
27+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
2128
</ItemGroup>
2229
</Project>

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "8.0.400"
3+
"version": "9.0.100"
44
}
55
}

src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
using System.Collections;
2-
using System.Collections.Generic;
32
using System.Diagnostics.CodeAnalysis;
4-
using System.Linq;
53
using System.Linq.Expressions;
64
using System.Reflection;
5+
using System.Runtime.CompilerServices;
76
using EntityFrameworkCore.Projectables.Extensions;
87
using Microsoft.EntityFrameworkCore.Metadata;
98
using Microsoft.EntityFrameworkCore.Query;
@@ -12,9 +11,10 @@ namespace EntityFrameworkCore.Projectables.Services
1211
{
1312
public sealed class ProjectableExpressionReplacer : ExpressionVisitor
1413
{
15-
readonly IProjectionExpressionResolver _resolver;
16-
readonly ExpressionArgumentReplacer _expressionArgumentReplacer = new();
17-
readonly Dictionary<MemberInfo, LambdaExpression?> _projectableMemberCache = new();
14+
private readonly IProjectionExpressionResolver _resolver;
15+
private readonly ExpressionArgumentReplacer _expressionArgumentReplacer = new();
16+
private readonly Dictionary<MemberInfo, LambdaExpression?> _projectableMemberCache = new();
17+
private IQueryProvider? _currentQueryProvider;
1818
private bool _disableRootRewrite;
1919
private IEntityType? _entityType;
2020

@@ -60,6 +60,9 @@ bool TryGetReflectedExpression(MemberInfo memberInfo, [NotNullWhen(true)] out La
6060
public Expression? Replace(Expression? node)
6161
{
6262
_disableRootRewrite = false;
63+
_currentQueryProvider = null;
64+
_entityType = null;
65+
6366
var ret = Visit(node);
6467

6568
if (_disableRootRewrite)
@@ -190,6 +193,29 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
190193

191194
protected override Expression VisitMember(MemberExpression node)
192195
{
196+
// Evaluate captured variables in closures that contain EF queries to inline them into the main query
197+
if (node.Expression is ConstantExpression constant &&
198+
constant.Type.Attributes.HasFlag(TypeAttributes.NestedPrivate) &&
199+
Attribute.IsDefined(constant.Type, typeof(CompilerGeneratedAttribute), inherit: true))
200+
{
201+
try
202+
{
203+
var value = Expression
204+
.Lambda<Func<object>>(Expression.Convert(node, typeof(object)))
205+
.Compile()
206+
.Invoke();
207+
208+
if (value is IQueryable queryable && ReferenceEquals(queryable.Provider, _currentQueryProvider))
209+
{
210+
return Visit(queryable.Expression);
211+
}
212+
}
213+
catch
214+
{
215+
// Ignore evaluation exceptions - continue with normal processing
216+
}
217+
}
218+
193219
var nodeExpression = node.Expression switch {
194220
UnaryExpression { NodeType: ExpressionType.Convert, Type: { IsInterface: true } type, Operand: { } operand }
195221
when type.IsAssignableFrom(operand.Type)
@@ -232,6 +258,7 @@ protected override Expression VisitExtension(Expression node)
232258
if (node is EntityQueryRootExpression root)
233259
{
234260
_entityType = root.EntityType;
261+
_currentQueryProvider = root.QueryProvider;
235262
}
236263

237264
return base.VisitExtension(node);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
DECLARE @__validArray_0 nvarchar(4000) = N'[1,2,3]';
2+
3+
SELECT [t].[Id]
4+
FROM [TestEntity] AS [t]
5+
WHERE [t].[Id] IN (
6+
SELECT [v].[value]
7+
FROM OPENJSON(@__validArray_0) WITH ([value] int '$') AS [v]
8+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
DECLARE @__validList_0 nvarchar(4000) = N'[1,2,3]';
2+
3+
SELECT [t].[Id]
4+
FROM [TestEntity] AS [t]
5+
WHERE [t].[Id] IN (
6+
SELECT [v].[value]
7+
FROM OPENJSON(@__validList_0) WITH ([value] int '$') AS [v]
8+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SELECT [t].[Id]
2+
FROM [TestEntity] AS [t]
3+
WHERE [t].[Id] IN (1, 2, 3)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
SELECT [o1].[RecordDate]
2+
FROM [User] AS [u]
3+
INNER JOIN (
4+
SELECT [o0].[RecordDate], [o0].[UserId]
5+
FROM (
6+
SELECT [o].[RecordDate], [o].[UserId], ROW_NUMBER() OVER(PARTITION BY [o].[UserId] ORDER BY [o].[RecordDate] DESC) AS [row]
7+
FROM [Order] AS [o]
8+
) AS [o0]
9+
WHERE [o0].[row] <= 2
10+
) AS [o1] ON [u].[Id] = [o1].[UserId]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
SELECT [o1].[Id], [o1].[RecordDate], [o1].[UserId]
2+
FROM [User] AS [u]
3+
LEFT JOIN (
4+
SELECT [o0].[Id], [o0].[RecordDate], [o0].[UserId]
5+
FROM (
6+
SELECT [o].[Id], [o].[RecordDate], [o].[UserId], ROW_NUMBER() OVER(PARTITION BY [o].[UserId] ORDER BY [o].[RecordDate] DESC) AS [row]
7+
FROM [Order] AS [o]
8+
) AS [o0]
9+
WHERE [o0].[row] <= 1
10+
) AS [o1] ON [u].[Id] = [o1].[UserId]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SELECT (
2+
SELECT TOP(1) [o].[RecordDate]
3+
FROM [Order] AS [o]
4+
WHERE [u].[Id] = [o].[UserId]
5+
ORDER BY [o].[RecordDate] DESC)
6+
FROM [User] AS [u]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SELECT [e].[Id] + 2
2+
FROM [Entity] AS [e]

0 commit comments

Comments
 (0)