diff --git a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs index 216a499..43c8121 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs +++ b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs @@ -226,7 +226,14 @@ x is IPropertySymbol xProperty && } else if (memberBody is PropertyDeclarationSyntax propertyDeclarationSyntax) { - if (propertyDeclarationSyntax.ExpressionBody is null) + var expressionBody = propertyDeclarationSyntax.ExpressionBody; + if (expressionBody is null) + { + //try to get from getter + var getter = propertyDeclarationSyntax.AccessorList?.Accessors.FirstOrDefault(x => x.Kind() == SyntaxKind.GetAccessorDeclaration); + expressionBody = getter?.ExpressionBody; + } + if (expressionBody is null) { var diagnostic = Diagnostic.Create(Diagnostics.RequiresExpressionBodyDefinition, propertyDeclarationSyntax.GetLocation(), memberSymbol.Name); context.ReportDiagnostic(diagnostic); @@ -236,7 +243,7 @@ x is IPropertySymbol xProperty && var returnType = declarationSyntaxRewriter.Visit(propertyDeclarationSyntax.Type); descriptor.ReturnTypeName = returnType.ToString(); - descriptor.ExpressionBody = (ExpressionSyntax)expressionSyntaxRewriter.Visit(propertyDeclarationSyntax.ExpressionBody.Expression); + descriptor.ExpressionBody = (ExpressionSyntax)expressionSyntaxRewriter.Visit(expressionBody.Expression); } else { diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.cs b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.cs index 140f7b2..f16be6c 100644 --- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.cs +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/StatefullPropertyTests.cs @@ -24,6 +24,13 @@ public record Entity [Projectable] public int Computed2 => Id * 2; + + [Projectable] + public int Alias + { + get => Id; + set => Id = value; + } } [Fact] @@ -80,5 +87,28 @@ public Task CombineSelectProjectableProperties() return Verifier.Verify(query.ToQueryString()); } + + + [Fact] + public Task FilterOnAliasProperty() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Where(x => x.Alias == 1); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SelectAliasProperty() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.Alias); + + return Verifier.Verify(query.ToQueryString()); + } } } diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedPropertyWithSetter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedPropertyWithSetter.verified.txt new file mode 100644 index 0000000..dccc517 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedPropertyWithSetter.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar; + } + } +} \ 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 36981f2..a5c1e09 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -127,6 +128,34 @@ class C { return Verifier.Verify(result.GeneratedTrees[0].ToString()); } + [Fact] + public Task SimpleProjectableComputedPropertyWithSetter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo + { + get => Bar; + set => Bar = value; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + [Fact] public Task SimpleProjectableComputedInNestedClassProperty() { @@ -470,28 +499,6 @@ static class C { return Verifier.Verify(result.GeneratedTrees[0].ToString()); } - [Fact] - public void BlockBodiedMember_RaisesDiagnostics() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo - { - get => 1; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Single(result.Diagnostics); - } - [Fact] public void BlockBodiedMethod_RaisesDiagnostics() { @@ -1617,7 +1624,7 @@ public Task GenericTypesWithConstraints() #region Helpers - Compilation CreateCompilation(string source, bool expectedToCompile = true) + Compilation CreateCompilation([StringSyntax("c#")]string source, bool expectedToCompile = true) { var references = Basic.Reference.Assemblies.NetStandard20.All.ToList(); references.Add(MetadataReference.CreateFromFile(typeof(ProjectableAttribute).Assembly.Location));