Skip to content

Commit d8339c7

Browse files
authored
Merge pull request #113 from koenbeuk/issue/109
Never map projectable properties
2 parents bd126fe + 6d8b621 commit d8339c7

File tree

4 files changed

+87
-0
lines changed

4 files changed

+87
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
8+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
9+
10+
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal;
11+
12+
public class ProjectablePropertiesNotMappedConvention : IEntityTypeAddedConvention
13+
{
14+
public void ProcessEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext<IConventionEntityTypeBuilder> context)
15+
{
16+
if (entityTypeBuilder.Metadata.ClrType is null)
17+
{
18+
return;
19+
}
20+
21+
foreach (var property in entityTypeBuilder.Metadata.ClrType.GetRuntimeProperties())
22+
{
23+
if (property.GetCustomAttribute<ProjectableAttribute>() is not null)
24+
{
25+
entityTypeBuilder.Ignore(property.Name);
26+
}
27+
}
28+
}
29+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
3+
4+
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal;
5+
6+
public class ProjectablePropertiesNotMappedConventionPlugin : IConventionSetPlugin
7+
{
8+
public ConventionSet ModifyConventions(ConventionSet conventionSet)
9+
{
10+
conventionSet.EntityTypeAddedConventions.Add(new ProjectablePropertiesNotMappedConvention());
11+
return conventionSet;
12+
}
13+
}

src/EntityFrameworkCore.Projectables/Infrastructure/Internal/ProjectionOptionsExtension.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using EntityFrameworkCore.Projectables.Infrastructure;
22
using EntityFrameworkCore.Projectables.Infrastructure.Internal;
33
using Microsoft.EntityFrameworkCore.Infrastructure;
4+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
5+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
46
using Microsoft.EntityFrameworkCore.Query;
57
using Microsoft.EntityFrameworkCore.Query.Internal;
68
using Microsoft.Extensions.DependencyInjection;
@@ -36,6 +38,9 @@ public ProjectionOptionsExtension(ProjectionOptionsExtension copyFrom)
3638
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Needed")]
3739
public void ApplyServices(IServiceCollection services)
3840
{
41+
// Register a convention that will ignore properties marked with the ProjectableAttribute
42+
services.AddScoped<IConventionSetPlugin, ProjectablePropertiesNotMappedConventionPlugin>();
43+
3944
static object CreateTargetInstance(IServiceProvider services, ServiceDescriptor descriptor)
4045
{
4146
if (descriptor.ImplementationInstance is not null)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using EntityFrameworkCore.Projectables.FunctionalTests.Helpers;
8+
9+
namespace EntityFrameworkCore.Projectables.FunctionalTests
10+
{
11+
public class EnumerableProjectableTests
12+
{
13+
public class Product
14+
{
15+
public int Id { get; set; }
16+
17+
public List<ProductPrice> Prices { get; } = [];
18+
19+
[Projectable]
20+
public IEnumerable<ProductPrice> CheapPrices => Prices.Where(x => x.Price < 10D);
21+
}
22+
23+
public class ProductPrice
24+
{
25+
public int Id { get; set; }
26+
27+
public double Price { get; set; }
28+
}
29+
30+
[Fact]
31+
public void ProjectableProperty_IsIgnoredFromMapping()
32+
{
33+
var dbContext = new SampleDbContext<Product>();
34+
var productPriceType = dbContext.Model.GetEntityTypes().Single(x => x.ClrType == typeof(ProductPrice));
35+
36+
// Assert 3 properties: Id, Price, ProductId (synthetic)
37+
Assert.Equal(3, productPriceType.GetProperties().Count());
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)