Skip to content

Commit

Permalink
Add .NET 9 + EF 9 support
Browse files Browse the repository at this point in the history
  • Loading branch information
wassim-k committed Nov 22, 2024
1 parent f826bb5 commit ee91f65
Show file tree
Hide file tree
Showing 64 changed files with 292 additions and 21 deletions.
31 changes: 19 additions & 12 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.7.9" />
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="ScenarioTests.XUnit" Version="1.0.1" />
<PackageVersion Include="Verify.Xunit" Version="22.5.0" />
<PackageVersion Include="xunit" Version="2.6.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.400"
"version": "9.0.100"
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using EntityFrameworkCore.Projectables.Extensions;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
Expand All @@ -12,9 +11,10 @@ namespace EntityFrameworkCore.Projectables.Services
{
public sealed class ProjectableExpressionReplacer : ExpressionVisitor
{
readonly IProjectionExpressionResolver _resolver;
readonly ExpressionArgumentReplacer _expressionArgumentReplacer = new();
readonly Dictionary<MemberInfo, LambdaExpression?> _projectableMemberCache = new();
private readonly IProjectionExpressionResolver _resolver;
private readonly ExpressionArgumentReplacer _expressionArgumentReplacer = new();
private readonly Dictionary<MemberInfo, LambdaExpression?> _projectableMemberCache = new();
private IQueryProvider? _currentQueryProvider;
private bool _disableRootRewrite;
private IEntityType? _entityType;

Expand Down Expand Up @@ -60,6 +60,9 @@ bool TryGetReflectedExpression(MemberInfo memberInfo, [NotNullWhen(true)] out La
public Expression? Replace(Expression? node)
{
_disableRootRewrite = false;
_currentQueryProvider = null;
_entityType = null;

var ret = Visit(node);

if (_disableRootRewrite)
Expand Down Expand Up @@ -190,6 +193,29 @@ protected override Expression VisitMethodCall(MethodCallExpression node)

protected override Expression VisitMember(MemberExpression node)
{
// Evaluate captured variables in closures that contain EF queries to inline them into the main query
if (node.Expression is ConstantExpression constant &&
constant.Type.Attributes.HasFlag(TypeAttributes.NestedPrivate) &&
Attribute.IsDefined(constant.Type, typeof(CompilerGeneratedAttribute), inherit: true))
{
try
{
var value = Expression
.Lambda<Func<object>>(Expression.Convert(node, typeof(object)))
.Compile()
.Invoke();

if (value is IQueryable queryable && ReferenceEquals(queryable.Provider, _currentQueryProvider))
{
return Visit(queryable.Expression);
}
}
catch
{
// Ignore evaluation exceptions - continue with normal processing
}
}

var nodeExpression = node.Expression switch {
UnaryExpression { NodeType: ExpressionType.Convert, Type: { IsInterface: true } type, Operand: { } operand }
when type.IsAssignableFrom(operand.Type)
Expand Down Expand Up @@ -232,6 +258,7 @@ protected override Expression VisitExtension(Expression node)
if (node is EntityQueryRootExpression root)
{
_entityType = root.EntityType;
_currentQueryProvider = root.QueryProvider;
}

return base.VisitExtension(node);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DECLARE @__validArray_0 nvarchar(4000) = N'[1,2,3]';

SELECT [t].[Id]
FROM [TestEntity] AS [t]
WHERE [t].[Id] IN (
SELECT [v].[value]
FROM OPENJSON(@__validArray_0) WITH ([value] int '$') AS [v]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DECLARE @__validList_0 nvarchar(4000) = N'[1,2,3]';

SELECT [t].[Id]
FROM [TestEntity] AS [t]
WHERE [t].[Id] IN (
SELECT [v].[value]
FROM OPENJSON(@__validList_0) WITH ([value] int '$') AS [v]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SELECT [t].[Id]
FROM [TestEntity] AS [t]
WHERE [t].[Id] IN (1, 2, 3)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SELECT [o1].[RecordDate]
FROM [User] AS [u]
INNER JOIN (
SELECT [o0].[RecordDate], [o0].[UserId]
FROM (
SELECT [o].[RecordDate], [o].[UserId], ROW_NUMBER() OVER(PARTITION BY [o].[UserId] ORDER BY [o].[RecordDate] DESC) AS [row]
FROM [Order] AS [o]
) AS [o0]
WHERE [o0].[row] <= 2
) AS [o1] ON [u].[Id] = [o1].[UserId]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SELECT [o1].[Id], [o1].[RecordDate], [o1].[UserId]
FROM [User] AS [u]
LEFT JOIN (
SELECT [o0].[Id], [o0].[RecordDate], [o0].[UserId]
FROM (
SELECT [o].[Id], [o].[RecordDate], [o].[UserId], ROW_NUMBER() OVER(PARTITION BY [o].[UserId] ORDER BY [o].[RecordDate] DESC) AS [row]
FROM [Order] AS [o]
) AS [o0]
WHERE [o0].[row] <= 1
) AS [o1] ON [u].[Id] = [o1].[UserId]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT (
SELECT TOP(1) [o].[RecordDate]
FROM [Order] AS [o]
WHERE [u].[Id] = [o].[UserId]
ORDER BY [o].[RecordDate] DESC)
FROM [User] AS [u]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id] + 2
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
SELECT [e1].[Id]
FROM [Entity] AS [e]
OUTER APPLY (
SELECT TOP(1) [e0].[Id]
FROM [Entity] AS [e0]
WHERE [e0].[Id] > [e].[Id]
) AS [e1]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id] * [e].[Id]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id] + 1
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id] + 1 + 1
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DECLARE @__key_0 varchar(11) = 'x';

SELECT [c].[Id]
FROM [ConcreteEntity] AS [c]
WHERE CONVERT(varchar(11), [c].[Id]) = @__key_0
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SELECT CASE
WHEN [e].[Id] >= 0 THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END, [e].[Id], [e].[Name]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT CAST(1 AS bit), [e].[Id], [e].[Name]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT CAST([c].[Age] AS float) / [c].[AverageLifespan] AS [LifeProgression], CAST([c].[MentalAge] AS float) / [c].[AverageLifespan] AS [MentalLifeProgression]
FROM [Cat] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 4
FROM [Concrete] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [Concrete] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [Concrete] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [MoreConcrete] AS [m]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [MoreConcrete] AS [m]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [Concrete] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 2
FROM [Concrete] AS [c]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SELECT [c].[Id]
FROM [BaseProvider] AS [b]
INNER JOIN [Concrete] AS [c] ON [b].[Id] = [c].[BaseProviderId]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SELECT [e].[Id], [e0].[Id] + 1, [e0].[Id]
FROM [Entity] AS [e]
LEFT JOIN [Entity] AS [e0] ON [e].[Id] = [e0].[EntityId]
ORDER BY [e].[Id]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Runtime.CompilerServices;

namespace EntityFrameworkCore.Projectables.FunctionalTests
{
public static class ModuleInitializer
{
[ModuleInitializer]
public static void Initialize()
{
#if !NET8_0
VerifierSettings.UniqueForTargetFrameworkAndVersion();
#endif
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 7
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT CAST(LEN([e].[Name]) AS int)
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SELECT [e2].[Id], [e2].[EntityId], [e2].[Name]
FROM [Entity] AS [e]
LEFT JOIN (
SELECT [e1].[Id], [e1].[EntityId], [e1].[Name]
FROM (
SELECT [e0].[Id], [e0].[EntityId], [e0].[Name], ROW_NUMBER() OVER(PARTITION BY [e0].[EntityId] ORDER BY [e0].[Id]) AS [row]
FROM [Entity] AS [e0]
) AS [e1]
WHERE 0 < [e1].[row] AND [e1].[row] <= 1
) AS [e2] ON [e].[Id] = [e2].[EntityId]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Name]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT CAST(LEN([e].[Name]) AS int)
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SELECT CAST(1 AS bit), [e].[Id], [e0].[Id], [e0].[EntityId], [e0].[Name], [e3].[Id], [e3].[EntityId], [e3].[Name]
FROM [Entity] AS [e]
LEFT JOIN [Entity] AS [e0] ON [e].[Id] = [e0].[EntityId]
LEFT JOIN (
SELECT [e2].[Id], [e2].[EntityId], [e2].[Name]
FROM (
SELECT [e1].[Id], [e1].[EntityId], [e1].[Name], ROW_NUMBER() OVER(PARTITION BY [e1].[EntityId] ORDER BY [e1].[Id]) AS [row]
FROM [Entity] AS [e1]
) AS [e2]
WHERE 0 < [e2].[row] AND [e2].[row] <= 1
) AS [e3] ON [e].[Id] = [e3].[EntityId]
ORDER BY [e].[Id]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Name]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id]
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT [e].[Id], (
SELECT COUNT(*)
FROM [Entity] AS [e0]
WHERE [e0].[Id] * 5 = 5) AS [TotalCount]
FROM [Entity] AS [e]
WHERE [e].[Id] * 5 = 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT [e].[Id], (
SELECT COUNT(*)
FROM [Entity] AS [e0]
WHERE [e0].[Id] * 5 = 5) AS [TotalCount]
FROM [Entity] AS [e]
WHERE [e].[Id] * 5 = 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT [e].[Id], [e].[Id] * 5
FROM [Entity] AS [e]
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Threading.Tasks;
using EntityFrameworkCore.Projectables.FunctionalTests.Helpers;
using Microsoft.EntityFrameworkCore;
using VerifyXunit;
using Xunit;

namespace EntityFrameworkCore.Projectables.FunctionalTests
{
Expand Down Expand Up @@ -35,5 +32,20 @@ public Task UseMemberPropertyQueryRootExpression()

return Verifier.Verify(query.ToQueryString());
}


[Fact]
public Task EntityRootSubqueryExpression()
{
using var dbContext = new SampleDbContext<Entity>();

var original = dbContext.Set<Entity>()
.Where(e => e.ComputedWithBacking == 5);

var query = original
.Select(e => new { Item = e, TotalCount = original.Count() });

return Verifier.Verify(query.ToQueryString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SELECT [e].[Id]
FROM [Entity] AS [e]
WHERE [e].[Id] + 1 = 2
Loading

0 comments on commit ee91f65

Please sign in to comment.