diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bfe3d4a..e260de9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -29,7 +29,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
@@ -49,7 +49,7 @@ jobs:
dotnet-version: 7.0.x
- name: Pack
run: |
- dotnet pack -v normal -c Debug --include-symbols --include-source -p:PackageVersion=2.0.0-pre-$GITHUB_RUN_ID -o nupkg
+ dotnet pack -v normal -c Debug --include-symbols --include-source -p:PackageVersion=4.0.0-pre-$GITHUB_RUN_ID -o nupkg
- name: Push to GitHub Feed
run: |
for f in ./nupkg/*.nupkg
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index cb67cf7..21792b5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -26,7 +26,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
include-prerelease: True
- name: Create Release NuGet package
run: |
diff --git a/Directory.Build.props b/Directory.Build.props
index 932ca59..b5a6e4e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,37 +1,21 @@
-
-
- true
- 11.0
- enable
- true
- CS1591
-
-
-
- Koen Bekkenutte
- MIT
- https://github.com/koenbeuk/EntityFrameworkCore.Projectables
- https://github.com/koenbeuk/EntityFrameworkCore.Projectables.git
- git
- https://github.com/koenbeuk/EntityFrameworkCore.Projectables/releases
- Project over properties and functions in your linq queries
-
-
- 4.0.1
+ net8.0
+ true
+ 12.0
+ enable
+ true
+ CS1591
+ enable
- net7.0;net6.0
- 6.0.0
- 6.0.0
- $(EFCoreVersion)
+ Koen Bekkenutte
+ MIT
+ https://github.com/koenbeuk/EntityFrameworkCore.Projectables
+ https://github.com/koenbeuk/EntityFrameworkCore.Projectables.git
+ git
+ https://github.com/koenbeuk/EntityFrameworkCore.Projectables/releases
+ Project over properties and functions in your linq queries
-
-
- 7.0.0
- $(EFCoreVersion)
-
-
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 0000000..d25f1f4
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,22 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EntityFrameworkCore.Projectables.sln b/EntityFrameworkCore.Projectables.sln
index e7424fc..687280f 100644
--- a/EntityFrameworkCore.Projectables.sln
+++ b/EntityFrameworkCore.Projectables.sln
@@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 17.0.31710.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A43F1828-D9B6-40F7-82B6-CA0070843E2F}"
+ ProjectSection(SolutionItems) = preProject
+ src\Directory.Build.props = src\Directory.Build.props
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F5E4436F-87F2-46AB-A9EB-59B4BF21BF7A}"
EndProject
@@ -21,8 +24,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.Project
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{07584D01-2D30-404B-B0D1-32080C0CC18A}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicSample", "samples\BasicSample\BasicSample.csproj", "{1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.Projectables.Abstractions", "src\EntityFrameworkCore.Projectables.Abstractions\EntityFrameworkCore.Projectables.Abstractions.csproj", "{C8038180-36F8-4077-922B-91F428EAC7D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.Projectables.Tests", "tests\EntityFrameworkCore.Projectables.Tests\EntityFrameworkCore.Projectables.Tests.csproj", "{2F0DD7D7-867F-4478-9E22-45C114B61C46}"
@@ -53,10 +54,6 @@ Global
{EE4D6CC1-78DE-4279-A567-C3D360C479F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE4D6CC1-78DE-4279-A567-C3D360C479F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE4D6CC1-78DE-4279-A567-C3D360C479F8}.Release|Any CPU.Build.0 = Release|Any CPU
- {1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9}.Release|Any CPU.Build.0 = Release|Any CPU
{C8038180-36F8-4077-922B-91F428EAC7D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8038180-36F8-4077-922B-91F428EAC7D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8038180-36F8-4077-922B-91F428EAC7D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -85,7 +82,6 @@ Global
{698E3EEC-64F9-4F96-B700-D61D04FD0704} = {A43F1828-D9B6-40F7-82B6-CA0070843E2F}
{20F85652-2923-4211-9262-C64BA8C9ED89} = {F5E4436F-87F2-46AB-A9EB-59B4BF21BF7A}
{EE4D6CC1-78DE-4279-A567-C3D360C479F8} = {A43F1828-D9B6-40F7-82B6-CA0070843E2F}
- {1B4A8710-4182-494D-B1C5-6B7CDB9C9DB9} = {07584D01-2D30-404B-B0D1-32080C0CC18A}
{C8038180-36F8-4077-922B-91F428EAC7D9} = {A43F1828-D9B6-40F7-82B6-CA0070843E2F}
{2F0DD7D7-867F-4478-9E22-45C114B61C46} = {F5E4436F-87F2-46AB-A9EB-59B4BF21BF7A}
{A36F5471-0C16-4453-811B-818326931313} = {F5E4436F-87F2-46AB-A9EB-59B4BF21BF7A}
diff --git a/README.md b/README.md
index f2c8b54..70f4181 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# EntitiyFrameworkCore.Projectables
-Flexible projection magic for EFCore
+Flexible projection magic for EF Core
[](https://www.nuget.org/packages/EntityFrameworkCore.Projectables.Abstractions/)
[](https://github.com/koenbeuk/EntityFrameworkCore.Projectables/actions/workflows/build.yml)
@@ -13,9 +13,9 @@ Flexible projection magic for EFCore
## Getting started
1. Install the package from [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Projectables/)
-2. Enable Projectables in your DbContext by calling: `dbContextOptions.UseProjectables()`
-3. Implement projectable properties and methods and mark them with the `[Projectable]` attribute.
-4. View our [samples](https://github.com/koenbeuk/EntityFrameworkCore.Projectables/tree/master/samples) and checkout our [Blog Post](https://onthedrift.com/posts/efcore-projectables/)
+2. Enable Projectables in your DbContext by adding: `dbContextOptions.UseProjectables()`
+3. Implement projectable properties and methods, marking them with the `[Projectable]` attribute.
+4. Explore our [samples](https://github.com/koenbeuk/EntityFrameworkCore.Projectables/tree/master/samples) and checkout our [Blog Post](https://onthedrift.com/posts/efcore-projectables/) for further guidance.
### Example
Assuming this sample:
@@ -64,38 +64,38 @@ SELECT (
WHERE (
SELECT TOP(1) [o0].[Id]
FROM [Orders] AS [o0]
- WHERE ([u].[Id] = [o0].[UserId]) AND [o0].[FulfilledDate] IS NOT NULL
- ORDER BY [o0].[CreatedDate] DESC) IS NOT NULL AND ((
+ WHERE [u].[Id] = [o0].[UserId] AND [o0].[FulfilledDate] IS NOT NULL
+ ORDER BY [o0].[CreatedDate] DESC) IS NOT NULL AND (
SELECT TOP(1) [o1].[Id]
FROM [Orders] AS [o1]
- WHERE ([u].[Id] = [o1].[UserId]) AND [o1].[FulfilledDate] IS NOT NULL
- ORDER BY [o1].[CreatedDate] DESC) = [o].[OrderId])) * (
+ WHERE [u].[Id] = [o1].[UserId] AND [o1].[FulfilledDate] IS NOT NULL
+ ORDER BY [o1].[CreatedDate] DESC) = [o].[OrderId]) * (
SELECT TOP(1) [o2].[TaxRate]
FROM [Orders] AS [o2]
- WHERE ([u].[Id] = [o2].[UserId]) AND [o2].[FulfilledDate] IS NOT NULL
+ WHERE [u].[Id] = [o2].[UserId] AND [o2].[FulfilledDate] IS NOT NULL
ORDER BY [o2].[CreatedDate] DESC) AS [GrandTotal]
FROM [Users] AS [u]
WHERE [u].[UserName] = @__sampleUser_UserName_0
```
-Projectable properties and methods have been inlined! the generated SQL could be improved but this is what EFCore (v5) gives us.
+Projectable properties and methods have been inlined! the generated SQL could be improved but this is what EF Core (v8) gives us.
### How it works
-Essentially there are 2 components: We have a source generator that is able to write companion Expression for properties and methods marked with the `Projectable` attribute. We then have a runtime component that intercepts any query and translates any call to a property or method marked with the `Projectable` attribute and translates the query to use the generated Expression instead.
+Essentially, there are two components: We have a source generator that can write companion expressions for properties and methods marked with the Projectable attribute. Then, we have a runtime component that intercepts any query and translates any call to a property or method marked with the Projectable attribute, translating the query to use the generated expression instead.
### FAQ
#### Are there currently any known limitations?
-There is currently no support for overloaded methods. Each method name needs to be unique within a given type.
+Currently, there is no support for overloaded methods. Each method name needs to be unique within a given type.
#### Is this specific to a database provider?
-No; The runtime component injects itself within the EFCore query compilation pipeline and thus has no impact on the database provider used. Of course you're still limited to whatever your database provider can do.
+No, the runtime component injects itself into the EFCore query compilation pipeline, thus having no impact on the database provider used. Of course, you're still limited to whatever your database provider can do.
#### Are there performance implications that I should be aware of?
-There are 2 compatibility modes: Limited and Full (Default). Most of the time, limited compatibility mode is sufficient however if you are running into issues with failed query compilation, then you may want to stick with Full compatibility mode. With Full compatibility mode, Each Query will first be expanded (Any calls to Projectable properties and methods will be replaced by their respective Expression) before being handed off to EFCore. (This is similar to how LinqKit/LinqExpander/Expressionify works). Because of this additional step, there is a small performance impact. Limited compatibility mode is smart about things and only expands the Query after it has been accepted by EF. The expanded query will then be stored in the Query Cache. With Limited compatibility you will likely see [increased](https://onthedrift.com/posts/efcore-projectables-perf/) performance over EFCore without projectables.
+There are two compatibility modes: Limited and Full (Default). Most of the time, limited compatibility mode is sufficient. However, if you are running into issues with failed query compilation, then you may want to stick with Full compatibility mode. With Full compatibility mode, each query will first be expanded (any calls to Projectable properties and methods will be replaced by their respective expression) before being handed off to EFCore. (This is similar to how LinqKit/LinqExpander/Expressionify works.) Because of this additional step, there is a small performance impact. Limited compatibility mode is smart about things and only expands the query after it has been accepted by EF. The expanded query will then be stored in the Query Cache. With Limited compatibility, you will likely see increased performance over EFCore without projectables.
#### Can I call additional properties and methods from my Projectable properties and methods?
-Yes you can! Any projectable property/method can call into other properties and methods as long as those properties/methods are native to EFCore or as long as they are marked with a `Projectable` attribute.
+Yes, you can! Any projectable property/method can call into other properties and methods as long as those properties/methods are native to EFCore or marked with a Projectable attribute.
#### Can I use projectable extensions methods on non-entity types?
Yes you can. It's perfectly acceptable to have the following code:
@@ -160,13 +160,13 @@ ORDER BY (COALESCE("u"."FirstName", '') || ' ') || COALESCE("u"."LastName", '')
```
#### How does this relate to [Expressionify](https://github.com/ClaveConsulting/Expressionify)?
-Expressionify is a project that was launched before this project. It has some overlapping features and uses similar approaches. When I first published this project, I was not aware of its existence so shame on me. Currently Expressionify targets a more focusses scope of what this project is doing and thereby it seems to be more limiting in its capabilities. Check them out though!
+Expressionify is a project that was launched before this project. It has some overlapping features and uses similar approaches. When I first published this project, I was not aware of its existence, so shame on me. Currently, Expressionify targets a more focused scope of what this project is doing, and thereby it seems to be more limiting in its capabilities. Check them out though!
#### How does this relate to LinqKit/LinqExpander/...?
-There are a few projects like [LinqKit](https://github.com/scottksmith95/LINQKit) that were created before we had code generators in dotnet. These are great options if you're stuck with classical EF or don't want to rely on code generation. Otherwise I would suggest that EntityFrameworkCore.Projectables and Expresssionify are superior approaches as they are able to rely on SourceGenerators to do most of the hard work.
+There are a few projects like [LinqKit](https://github.com/scottksmith95/LINQKit) that were created before we had source generators in .NET. These are great options if you're stuck with classical EF or don't want to rely on code generation. Otherwise, I would suggest that EntityFrameworkCore.Projectables and Expressionify are superior approaches as they can rely on SourceGenerators to do most of the hard work.
#### Is the available for EFCore 3.1, 5 and 6?
-Yes it is! there is no difference between any of these versions and you can upgrade/downgrade whenever you want.
+V1 is targeting EF Core 5 and 3.1. V2 and V3 are targeting EF Core 6 and are compatible with EF Core 7. You can upgrade/downgrade between these versions based on your EF Core version requirements.
#### What is next for this project?
-TBD... However one thing I'd like to improve is our Expression generation logic as its currently making a few assumptions (have yet to experience it breaking). Community contributions are very welcome!
+TBD... However, one thing I'd like to improve is our expression generation logic as it's currently making a few assumptions (have yet to experience it breaking). Community contributions are very welcome!
\ No newline at end of file
diff --git a/benchmarks/EntityFrameworkCore.Projectables.Benchmarks/EntityFrameworkCore.Projectables.Benchmarks.csproj b/benchmarks/EntityFrameworkCore.Projectables.Benchmarks/EntityFrameworkCore.Projectables.Benchmarks.csproj
index b7fe63e..345c4c2 100644
--- a/benchmarks/EntityFrameworkCore.Projectables.Benchmarks/EntityFrameworkCore.Projectables.Benchmarks.csproj
+++ b/benchmarks/EntityFrameworkCore.Projectables.Benchmarks/EntityFrameworkCore.Projectables.Benchmarks.csproj
@@ -1,19 +1,18 @@
- Exe
- net7.0
- false
+ Exe
+ false
-
-
+
+
-
-
+
+
diff --git a/samples/BasicSample/BasicSample.csproj b/samples/BasicSample/BasicSample.csproj
deleted file mode 100644
index 937f9ed..0000000
--- a/samples/BasicSample/BasicSample.csproj
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- Exe
- net7.0
- disable
- true
- $(BaseIntermediateOutputPath)Generated
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/BasicSample/Program.cs b/samples/BasicSample/Program.cs
deleted file mode 100644
index d724d99..0000000
--- a/samples/BasicSample/Program.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations.Schema;
-using System.Linq;
-using EntityFrameworkCore.Projectables;
-using Microsoft.Data.Sqlite;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace BasicSample
-{
- public class User
- {
- public int Id { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
-
- public ICollection Orders { get; set; }
-
- [Projectable(UseMemberBody = nameof(_FullName))]
- public string FullName { get; set; }
- private string _FullName => FirstName + " " + LastName;
-
- [Projectable(UseMemberBody = nameof(_TotalSpent))]
- public double TotalSpent { get; set; }
- private double _TotalSpent => Orders.Sum(x => x.PriceSum);
-
- [Projectable]
- public Order MostValuableOrder
- => Orders.OrderByDescending(x => x.PriceSum).FirstOrDefault();
-
- [Projectable]
- public IEnumerable FindOrderedProducts(string namePrefix)
- => Orders.SelectMany(x => x.Items).Select(x => x.Product).Where(x => x.Name.StartsWith(namePrefix));
- }
-
- public class Product
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public double Price { get; set; }
- }
-
- public class Order
- {
- public int OrderId { get; set; }
- public int ProductId { get; set; }
- public ICollection Items { get; set; }
-
- [Projectable]
- public double PriceSum => Items.Sum(x => x.TotalPrice);
- }
-
- public class OrderItem
- {
- public int OrderId { get; set; }
- public int ProductId { get; set; }
- public int Quantity { get; set; }
- public double UnitPrice { get; set; }
-
- public Order Order { get; set; }
- public Product Product { get; set; }
-
- [Projectable]
- public double TotalPrice => Quantity * UnitPrice;
- }
-
- public class ApplicationDbContext : DbContext
- {
- public ApplicationDbContext(DbContextOptions options) : base(options)
- {
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity().HasKey(x => new { x.OrderId, x.ProductId });
- }
-
- public DbSet Users { get; set; }
- }
-
-
- class Program
- {
- public static void Main(string[] args)
- {
- using var dbConnection = new SqliteConnection("Filename=:memory:");
- dbConnection.Open();
-
- using var serviceProvider = new ServiceCollection()
- .AddDbContext((provider, options) => {
- options
- .UseSqlite(dbConnection)
- // .LogTo(Console.WriteLine)
- .EnableSensitiveDataLogging()
- .UseProjectables();
- })
- .BuildServiceProvider();
-
- var dbContext = serviceProvider.GetRequiredService();
- dbContext.Database.EnsureCreated();
-
- var product1 = new Product { Name = "Red pen", Price = 1.5 };
- var product2 = new Product { Name = "Blue pen", Price = 2.1 };
-
- var user = new User {
- FirstName = "Jon",
- LastName = "Doe",
- Orders = new List {
- new Order {
- Items = new List {
- new OrderItem {
- Product = product1,
- UnitPrice = product1.Price,
- Quantity = 1
- },
- new OrderItem {
- Product = product2,
- UnitPrice = product2.Price,
- Quantity = 2
- }
- }
- }
- }
- };
-
- dbContext.Users.Add(user);
- dbContext.SaveChanges();
-
- // What did our user spent in total
-
- {
- foreach (var u in dbContext.Users)
- {
- Console.WriteLine($"User name: {u.FullName}");
- }
-
- foreach (var u in dbContext.Users.ToList())
- {
- Console.WriteLine($"User name: {u.FullName}");
- }
-
- foreach (var u in dbContext.Users.OrderBy(x => x.FullName))
- {
- Console.WriteLine($"User name: {u.FullName}");
- }
- }
-
- {
- foreach (var u in dbContext.Users.Where(x => x.TotalSpent >= 1))
- {
- Console.WriteLine($"User name: {u.FullName}");
- }
- }
-
- {
- var result = dbContext.Users.FirstOrDefault();
- Console.WriteLine($"Our first user {result.FullName} has spent {result.TotalSpent}");
-
- result = dbContext.Users.FirstOrDefault(x => x.TotalSpent > 1);
- Console.WriteLine($"Our first user {result.FullName} has spent {result.TotalSpent}");
-
- var spent = dbContext.Users.Sum(x => x.TotalSpent);
- Console.WriteLine($"Our users combined spent: {spent}");
- }
-
- {
- var query = dbContext.Users
- .Select(x => new {
- Name = x.FullName,
- x.TotalSpent
- });
-
- var result = query.FirstOrDefault();
-
- Console.WriteLine($"Our user ({result.Name}) spent {result.TotalSpent}");
- }
-
- {
- var query = dbContext.Users
- .Select(x => new {
- Name = x.FullName,
- x.MostValuableOrder
- });
-
- var result = query.FirstOrDefault();
-
- Console.WriteLine($"Our users spent {result.MostValuableOrder.PriceSum} on its biggest order");
- }
-
- {
- var query = dbContext.Users
- .Select(x => new {
- Name = x.FullName,
- Ordered = x.FindOrderedProducts("Red").Select(x => x.Name)
- });
-
- var result = query.FirstOrDefault();
-
- Console.WriteLine($"Our users bought the following products starting with 'Red': {string.Join(", ", result.Ordered)}");
- }
-
- {
- var ret = dbContext.Users
- .Include(x => x.Orders)
- .ThenInclude(x => x.Items)
- .ThenInclude(x => x.Product)
- .First();
- Console.WriteLine($"User name: {ret.FullName}, Orders: {string.Join(", ", ret.Orders
- .SelectMany(x => x.Items
- .Select(y => y.Product.Name)
- ))}");
- }
-
- }
- }
-}
diff --git a/samples/ReadmeSample/Program.cs b/samples/ReadmeSample/Program.cs
index 074967c..ca24270 100644
--- a/samples/ReadmeSample/Program.cs
+++ b/samples/ReadmeSample/Program.cs
@@ -1,47 +1,35 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.EntityFrameworkCore;
+using ReadmeSample;
using ReadmeSample.Entities;
using ReadmeSample.Extensions;
-namespace ReadmeSample
-{
- class Program
- {
- static void Main(string[] args)
- {
- using var dbContext = new ApplicationDbContext();
+using var dbContext = new ApplicationDbContext();
- // recreate database
- dbContext.Database.EnsureDeleted();
- dbContext.Database.EnsureCreated();
+// recreate database
+dbContext.Database.EnsureDeleted();
+dbContext.Database.EnsureCreated();
- // Populate with seed data
- var sampleUser = new User { UserName = "Jon", EmailAddress = "jon@doe.com" };
- var sampleProduct = new Product { Name = "Blue Pen", ListPrice = 1.5m };
- var sampleOrder = new Order {
- User = sampleUser,
- TaxRate = .19m,
- CreatedDate = DateTime.UtcNow.AddDays(-1),
- FulfilledDate = DateTime.UtcNow,
- Items = new List {
- new OrderItem { Product = sampleProduct, Quantity = 5 }
- }
- };
+// Populate with seed data
+var sampleUser = new User { UserName = "Jon", EmailAddress = "jon@doe.com" };
+var sampleProduct = new Product { Name = "Blue Pen", ListPrice = 1.5m };
+var sampleOrder = new Order {
+ User = sampleUser,
+ TaxRate = .19m,
+ CreatedDate = DateTime.UtcNow.AddDays(-1),
+ FulfilledDate = DateTime.UtcNow,
+ Items = new List {
+ new OrderItem { Product = sampleProduct, Quantity = 5 }
+ }
+};
- dbContext.AddRange(sampleUser, sampleProduct, sampleOrder);
- dbContext.SaveChanges();
+dbContext.AddRange(sampleUser, sampleProduct, sampleOrder);
+dbContext.SaveChanges();
- var query = dbContext.Users
- .Where(x => x.UserName == sampleUser.UserName)
- .Select(x => new {
- GrandTotal = x.GetMostRecentOrderForUser(/* includeUnfulfilled: */ false).GrandTotal
- });
+var query = dbContext.Users
+ .Where(x => x.UserName == sampleUser.UserName)
+ .Select(x => new {
+ GrandTotal = x.GetMostRecentOrderForUser(/* includeUnfulfilled: */ false).GrandTotal
+ });
- var result = query.First();
+var result = query.First();
- Console.WriteLine($"Jons latest order had a grant total of {result.GrandTotal}");
- }
- }
-}
+Console.WriteLine($"Jons latest order had a grant total of {result.GrandTotal}");
diff --git a/samples/ReadmeSample/ReadmeSample.csproj b/samples/ReadmeSample/ReadmeSample.csproj
index 2da4034..b1dc659 100644
--- a/samples/ReadmeSample/ReadmeSample.csproj
+++ b/samples/ReadmeSample/ReadmeSample.csproj
@@ -1,23 +1,19 @@
- Exe
- net6.0
- disable
- true
- $(BaseIntermediateOutputPath)Generated
- false
+ Exe
+ disable
+ false
-
-
-
+
+
-
-
+
+
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index 3ee0422..0000000
--- a/shell.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{pkgs ? import {}}: let
- dotnet = with pkgs.dotnetCorePackages;
- combinePackages [
- sdk_7_0
- aspnetcore_7_0
- ];
-in
- pkgs.mkShell {
- packages = [dotnet];
-
- DOTNET_ROOT = "${dotnet}";
- }
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index f1028a3..cb86060 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,28 +1,27 @@
-
- true
- snupkg
+ true
+ snupkg
- true
- ../../Key.snk
+ true
+ ../../Key.snk
- true
- true
- $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ true
+ true
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
- true
+ true
-
+
diff --git a/src/EntityFrameworkCore.Projectables.Abstractions/EntityFrameworkCore.Projectables.Abstractions.csproj b/src/EntityFrameworkCore.Projectables.Abstractions/EntityFrameworkCore.Projectables.Abstractions.csproj
index 50ff9ed..117e7d8 100644
--- a/src/EntityFrameworkCore.Projectables.Abstractions/EntityFrameworkCore.Projectables.Abstractions.csproj
+++ b/src/EntityFrameworkCore.Projectables.Abstractions/EntityFrameworkCore.Projectables.Abstractions.csproj
@@ -1,26 +1,25 @@
- netstandard2.0
- EntityFrameworkCore.Projectables
- README.md
+ EntityFrameworkCore.Projectables
+ README.md
-
- false
- Content
- PreserveNewest
-
+
+ false
+ Content
+ PreserveNewest
+
-
+
-
-
+
+
-
+
diff --git a/src/EntityFrameworkCore.Projectables.Generator/EntityFrameworkCore.Projectables.Generator.csproj b/src/EntityFrameworkCore.Projectables.Generator/EntityFrameworkCore.Projectables.Generator.csproj
index fd91bc6..2bab29f 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/EntityFrameworkCore.Projectables.Generator.csproj
+++ b/src/EntityFrameworkCore.Projectables.Generator/EntityFrameworkCore.Projectables.Generator.csproj
@@ -1,18 +1,19 @@
- netstandard2.0
- $(NoWarn);NU5128
- false
+ netstandard2.0
+ $(NoWarn);NU5128
+ false
+ true
-
-
+
+
-
-
+
+
diff --git a/src/EntityFrameworkCore.Projectables/EntityFrameworkCore.Projectables.csproj b/src/EntityFrameworkCore.Projectables/EntityFrameworkCore.Projectables.csproj
index 9aa456d..4be6e6b 100644
--- a/src/EntityFrameworkCore.Projectables/EntityFrameworkCore.Projectables.csproj
+++ b/src/EntityFrameworkCore.Projectables/EntityFrameworkCore.Projectables.csproj
@@ -1,12 +1,10 @@
-
- net7.0;net6.0
README.md
-
+
@@ -16,6 +14,4 @@
-
-
diff --git a/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs b/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs
index 3eedc6d..c9d8ad4 100644
--- a/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs
+++ b/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs
@@ -229,14 +229,11 @@ PropertyInfo property when nodeExpression is not null
protected override Expression VisitExtension(Expression node)
{
-#if NET7_0_OR_GREATER
if (node is EntityQueryRootExpression root)
-#else
- if (node is QueryRootExpression root)
-#endif
{
_entityType = root.EntityType;
}
+
return base.VisitExtension(node);
}
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ArrayOfPrimitivesArguments.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ArrayOfPrimitivesArguments.verified.txt
index ad0d728..f576f74 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ArrayOfPrimitivesArguments.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ArrayOfPrimitivesArguments.verified.txt
@@ -1,3 +1,8 @@
+DECLARE @__validArray_0 nvarchar(4000) = N'[1,2,3]';
+
SELECT [t].[Id]
FROM [TestEntity] AS [t]
-WHERE [t].[Id] IN (1, 2, 3)
\ No newline at end of file
+WHERE [t].[Id] IN (
+ SELECT [v].[value]
+ FROM OPENJSON(@__validArray_0) WITH ([value] int '$') AS [v]
+)
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ListOfPrimitivesArguments.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ListOfPrimitivesArguments.verified.txt
index ad0d728..454dc2d 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ListOfPrimitivesArguments.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexArgumentsTests.ListOfPrimitivesArguments.verified.txt
@@ -1,3 +1,8 @@
+DECLARE @__validList_0 nvarchar(4000) = N'[1,2,3]';
+
SELECT [t].[Id]
FROM [TestEntity] AS [t]
-WHERE [t].[Id] IN (1, 2, 3)
\ No newline at end of file
+WHERE [t].[Id] IN (
+ SELECT [v].[value]
+ FROM OPENJSON(@__validList_0) WITH ([value] int '$') AS [v]
+)
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/EntityFrameworkCore.Projectables.FunctionalTests.csproj b/tests/EntityFrameworkCore.Projectables.FunctionalTests/EntityFrameworkCore.Projectables.FunctionalTests.csproj
index 0c895e5..bb5b0c5 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/EntityFrameworkCore.Projectables.FunctionalTests.csproj
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/EntityFrameworkCore.Projectables.FunctionalTests.csproj
@@ -1,36 +1,33 @@
- net7.0
- false
- true
- $(BaseIntermediateOutputPath)Generated
+ false
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
-
+
+
-
-
+
+
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ExtensionsMethods/ExtensionMethodTests.SelectProjectableExtensionMethod2.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ExtensionsMethods/ExtensionMethodTests.SelectProjectableExtensionMethod2.verified.txt
index a9241ac..312219c 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/ExtensionsMethods/ExtensionMethodTests.SelectProjectableExtensionMethod2.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/ExtensionsMethods/ExtensionMethodTests.SelectProjectableExtensionMethod2.verified.txt
@@ -1,2 +1,2 @@
-SELECT ([e].[Id] + 1) + 1
+SELECT [e].[Id] + 1 + 1
FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/IngoreNullConditionalRewriteTests.RelationalExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/IngoreNullConditionalRewriteTests.RelationalExpression.verified.txt
index a80b047..db121ad 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/IngoreNullConditionalRewriteTests.RelationalExpression.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/IngoreNullConditionalRewriteTests.RelationalExpression.verified.txt
@@ -1,4 +1,10 @@
-SELECT [e].[Id], [e0].[Id], [e0].[EntityId], [e0].[Name]
+SELECT [t0].[Id], [t0].[EntityId], [t0].[Name]
FROM [Entity] AS [e]
-LEFT JOIN [Entity] AS [e0] ON [e].[Id] = [e0].[EntityId]
-ORDER BY [e].[Id]
\ No newline at end of file
+LEFT JOIN (
+ SELECT [t].[Id], [t].[EntityId], [t].[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 [t]
+ WHERE 0 < [t].[row] AND [t].[row] <= 1
+) AS [t0] ON [e].[Id] = [t0].[EntityId]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/RewriteNullConditionalRewriteTests.RelationalExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/RewriteNullConditionalRewriteTests.RelationalExpression.verified.txt
index 44b3cf9..3844897 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/RewriteNullConditionalRewriteTests.RelationalExpression.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/NullConditionals/RewriteNullConditionalRewriteTests.RelationalExpression.verified.txt
@@ -1,5 +1,12 @@
-SELECT CAST(1 AS bit), [e].[Id], [e0].[Id], [e0].[EntityId], [e0].[Name], [e1].[Id], [e1].[EntityId], [e1].[Name]
+SELECT CAST(1 AS bit), [e].[Id], [e0].[Id], [e0].[EntityId], [e0].[Name], [t0].[Id], [t0].[EntityId], [t0].[Name]
FROM [Entity] AS [e]
LEFT JOIN [Entity] AS [e0] ON [e].[Id] = [e0].[EntityId]
-LEFT JOIN [Entity] AS [e1] ON [e].[Id] = [e1].[EntityId]
-ORDER BY [e].[Id], [e0].[Id]
\ No newline at end of file
+LEFT JOIN (
+ SELECT [t].[Id], [t].[EntityId], [t].[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 [t]
+ WHERE 0 < [t].[row] AND [t].[row] <= 1
+) AS [t0] ON [e].[Id] = [t0].[EntityId]
+ORDER BY [e].[Id]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullComplexFunctionTests.FilterOnProjectableProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullComplexFunctionTests.FilterOnProjectableProperty.verified.txt
index d326188..0fff6cc 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullComplexFunctionTests.FilterOnProjectableProperty.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullComplexFunctionTests.FilterOnProjectableProperty.verified.txt
@@ -1,3 +1,3 @@
SELECT [e].[Id]
FROM [Entity] AS [e]
-WHERE ([e].[Id] + 1) = 2
\ No newline at end of file
+WHERE [e].[Id] + 1 = 2
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.CombineSelectProjectableProperties.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.CombineSelectProjectableProperties.verified.txt
index 1a54cac..b2ed8fe 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.CombineSelectProjectableProperties.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.CombineSelectProjectableProperties.verified.txt
@@ -1,2 +1,2 @@
-SELECT [e].[Id] + ([e].[Id] * 2)
+SELECT [e].[Id] + [e].[Id] * 2
FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.FilterOnComplexProjectableProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.FilterOnComplexProjectableProperty.verified.txt
index 8541873..bbcfbc2 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.FilterOnComplexProjectableProperty.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.FilterOnComplexProjectableProperty.verified.txt
@@ -1,3 +1,3 @@
SELECT [e].[Id]
FROM [Entity] AS [e]
-WHERE ([e].[Id] * 2) = 2
\ No newline at end of file
+WHERE [e].[Id] * 2 = 2
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.CombineSelectProjectableProperties.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.CombineSelectProjectableProperties.verified.txt
index 1a54cac..b2ed8fe 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.CombineSelectProjectableProperties.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.CombineSelectProjectableProperties.verified.txt
@@ -1,2 +1,2 @@
-SELECT [e].[Id] + ([e].[Id] * 2)
+SELECT [e].[Id] + [e].[Id] * 2
FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.FilterOnComplexProjectableProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.FilterOnComplexProjectableProperty.verified.txt
index 8541873..bbcfbc2 100644
--- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.FilterOnComplexProjectableProperty.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullSimpleFunctionTests.FilterOnComplexProjectableProperty.verified.txt
@@ -1,3 +1,3 @@
SELECT [e].[Id]
FROM [Entity] AS [e]
-WHERE ([e].[Id] * 2) = 2
\ No newline at end of file
+WHERE [e].[Id] * 2 = 2
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/EntityFrameworkCore.Projectables.Generator.Tests.csproj b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EntityFrameworkCore.Projectables.Generator.Tests.csproj
index 3e97fcf..5db427d 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/EntityFrameworkCore.Projectables.Generator.Tests.csproj
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EntityFrameworkCore.Projectables.Generator.Tests.csproj
@@ -1,31 +1,29 @@
- net7.0
- false
+ false
-
-
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt
index 30a1294..bb4a054 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt
@@ -14,7 +14,9 @@ namespace EntityFrameworkCore.Projectables.Generated
static global::System.Linq.Expressions.Expression> Expression()
{
return (global::Foo.EntityExtensions.Entity entity) => new global::Foo.EntityExtensions.Entity(entity.Id)
- {FullName = entity.FullName};
+ {
+ FullName = entity.FullName
+ };
}
}
}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
index b79842d..dd69903 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
@@ -1748,7 +1748,7 @@ public Task GenericTypesWithConstraints()
Compilation CreateCompilation(string source, bool expectedToCompile = true)
{
- var references = Basic.Reference.Assemblies.NetStandard20.All.ToList();
+ var references = Basic.Reference.Assemblies.Net80.References.All.ToList();
references.Add(MetadataReference.CreateFromFile(typeof(ProjectableAttribute).Assembly.Location));
var compilation = CSharpCompilation.Create("compilation",
diff --git a/tests/EntityFrameworkCore.Projectables.Tests/EntityFrameworkCore.Projectables.Tests.csproj b/tests/EntityFrameworkCore.Projectables.Tests/EntityFrameworkCore.Projectables.Tests.csproj
index d214161..b7ae079 100644
--- a/tests/EntityFrameworkCore.Projectables.Tests/EntityFrameworkCore.Projectables.Tests.csproj
+++ b/tests/EntityFrameworkCore.Projectables.Tests/EntityFrameworkCore.Projectables.Tests.csproj
@@ -1,27 +1,26 @@
- net7.0
- false
- true
-
-
+ false
+
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+