diff --git a/README.md b/README.md
index ab688bf..2f06978 100644
--- a/README.md
+++ b/README.md
@@ -159,6 +159,36 @@ GROUP BY (COALESCE("u"."FirstName", '') || ' ') || COALESCE("u"."LastName", '')
ORDER BY (COALESCE("u"."FirstName", '') || ' ') || COALESCE("u"."LastName", '')
```
+#### Can I use block-bodied methods instead of expression-bodied methods?
+Yes! As of version 6.x, you can now use traditional block-bodied methods with `[Projectable]`. This makes code more readable when dealing with complex conditional logic:
+
+```csharp
+// Expression-bodied (still supported)
+[Projectable]
+public string Level() => Value > 100 ? "High" : Value > 50 ? "Medium" : "Low";
+
+// Block-bodied (now also supported!)
+[Projectable]
+public string Level()
+{
+ if (Value > 100)
+ return "High";
+ else if (Value > 50)
+ return "Medium";
+ else
+ return "Low";
+}
+```
+
+Both generate identical SQL. Block-bodied methods support:
+- If-else statements (converted to ternary/CASE expressions)
+- Switch statements
+- Local variables (automatically inlined)
+- Simple return statements
+
+The generator will also detect and report side effects (assignments, method calls to non-projectable methods, etc.) with precise error messages. See [Block-Bodied Methods Documentation](docs/BlockBodiedMethods.md) for complete details.
+
+
#### How do I expand enum extension methods?
When you have an enum property and want to call an extension method on it (like getting a display name from a `[Display]` attribute), you can use the `ExpandEnumMethods` property on the `[Projectable]` attribute. This will expand the enum method call into a chain of ternary expressions for each enum value, allowing EF Core to translate it to SQL CASE expressions.
diff --git a/docs/BlockBodiedMethods.md b/docs/BlockBodiedMethods.md
new file mode 100644
index 0000000..12c0022
--- /dev/null
+++ b/docs/BlockBodiedMethods.md
@@ -0,0 +1,383 @@
+# Block-Bodied Methods Support
+
+As of this version, EntityFrameworkCore.Projectables now supports "classic" block-bodied methods decorated with `[Projectable]`, in addition to expression-bodied methods.
+
+## What's Supported
+
+Block-bodied methods can now be transformed into expression trees when they contain:
+
+### 1. Simple Return Statements
+```csharp
+[Projectable]
+public int GetConstant()
+{
+ return 42;
+}
+```
+
+### 2. If-Else Statements (converted to ternary expressions)
+```csharp
+[Projectable]
+public string GetCategory()
+{
+ if (Value > 100)
+ {
+ return "High";
+ }
+ else
+ {
+ return "Low";
+ }
+}
+```
+
+### 3. Nested If-Else Statements
+```csharp
+[Projectable]
+public string GetLevel()
+{
+ if (Value > 100)
+ {
+ return "High";
+ }
+ else if (Value > 50)
+ {
+ return "Medium";
+ }
+ else
+ {
+ return "Low";
+ }
+}
+```
+
+### 4. Local Variable Declarations (inlined into the expression)
+```csharp
+[Projectable]
+public int CalculateDouble()
+{
+ var doubled = Value * 2;
+ return doubled + 5;
+}
+
+// Transitive inlining is also supported:
+[Projectable]
+public int CalculateComplex()
+{
+ var a = Value * 2;
+ var b = a + 5;
+ return b + 10; // Fully expanded to: Value * 2 + 5 + 10
+}
+```
+
+**⚠️ Important Notes:**
+- Local variables are inlined at each usage point, which duplicates the initializer expression
+- If a local variable is used multiple times, its initializer expression is duplicated at each usage, which can change semantics if the initializer has side effects
+- Local variables can only be declared at the method body level, not inside nested blocks (if/switch/etc.)
+- Variables are fully expanded transitively (variables that reference other variables are fully inlined)
+
+### 5. Switch Statements (converted to nested ternary expressions)
+```csharp
+[Projectable]
+public string GetValueLabel()
+{
+ switch (Value)
+ {
+ case 1:
+ return "One";
+ case 2:
+ return "Two";
+ case 3:
+ return "Three";
+ default:
+ return "Many";
+ }
+}
+```
+
+### 6. If Statements Without Else (uses default value)
+```csharp
+// Pattern 1: Explicit null return
+[Projectable]
+public int? GetPremiumIfActive()
+{
+ if (IsActive)
+ {
+ return Value * 2;
+ }
+ return null; // Explicit return for all code paths
+}
+
+// Pattern 2: Explicit fallback return
+[Projectable]
+public string GetStatus()
+{
+ if (IsActive)
+ {
+ return "Active";
+ }
+ return "Inactive"; // Explicit fallback
+}
+```
+
+### 7. Multiple Early Returns (converted to nested ternary expressions)
+```csharp
+[Projectable]
+public string GetValueCategory()
+{
+ if (Value > 100)
+ {
+ return "Very High";
+ }
+
+ if (Value > 50)
+ {
+ return "High";
+ }
+
+ if (Value > 10)
+ {
+ return "Medium";
+ }
+
+ return "Low";
+}
+
+// Converted to: Value > 100 ? "Very High" : (Value > 50 ? "High" : (Value > 10 ? "Medium" : "Low"))
+```
+
+## Limitations and Warnings
+
+The source generator will produce **warning EFP0003** when it encounters unsupported statements in block-bodied methods:
+
+### Unsupported Statements:
+- While, for, foreach loops
+- Try-catch-finally blocks
+- Throw statements
+- New object instantiation in statement position
+
+### Example of Unsupported Pattern:
+```csharp
+[Projectable]
+public int GetValue()
+{
+ for (int i = 0; i < 10; i++) // ❌ Loops not supported
+ {
+ // ...
+ }
+ return 0;
+}
+```
+
+Supported patterns:
+```csharp
+[Projectable]
+public int GetValue()
+{
+ if (IsActive) // ✅ If without else is now supported!
+ {
+ return Value;
+ }
+ else
+ {
+ return 0;
+ }
+}
+```
+
+Additional supported patterns:
+```csharp
+// If without else using fallback return:
+[Projectable]
+public int GetValue()
+{
+ if (IsActive)
+ {
+ return Value;
+ }
+ return 0; // ✅ Fallback return
+}
+
+// Switch statement:
+[Projectable]
+public string GetLabel()
+{
+ switch (Value) // ✅ Switch statements now supported!
+ {
+ case 1:
+ return "One";
+ case 2:
+ return "Two";
+ default:
+ return "Other";
+ }
+}
+```
+
+Or as expression-bodied:
+```csharp
+[Projectable]
+public int GetValue() => IsActive ? Value : 0; // ✅ Expression-bodied
+```
+
+## How It Works
+
+The source generator:
+1. Parses block-bodied methods
+2. Converts if-else statements to conditional (ternary) expressions
+3. Converts switch statements to nested conditional expressions
+4. Inlines local variables into the return expression
+5. Rewrites the resulting expression using the existing expression transformation pipeline
+6. Generates the same output as expression-bodied methods
+
+## Benefits
+
+- **More readable code**: Complex logic with nested conditions and switch statements is often easier to read than nested ternary operators
+- **Gradual migration**: Existing code with block bodies can now be marked as `[Projectable]` without rewriting
+- **Intermediate variables**: Local variables can make complex calculations more understandable
+- **Switch support**: Traditional switch statements now work alongside switch expressions
+
+## SQL Output Examples
+
+### Switch Statement with Multiple Cases
+Given this code:
+```csharp
+switch (Value)
+{
+ case 1:
+ case 2:
+ return "Low";
+ case 3:
+ case 4:
+ case 5:
+ return "Medium";
+ default:
+ return "High";
+}
+```
+
+Generates optimized SQL:
+```sql
+SELECT CASE
+ WHEN [e].[Value] IN (1, 2) THEN N'Low'
+ WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium'
+ ELSE N'High'
+END
+FROM [Entity] AS [e]
+```
+
+### If-Else Example Output
+
+Given this code:
+```csharp
+public record Entity
+{
+ public int Value { get; set; }
+ public bool IsActive { get; set; }
+
+ [Projectable]
+ public int GetAdjustedValue()
+ {
+ if (IsActive && Value > 0)
+ {
+ return Value * 2;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+```
+
+The generated SQL will be:
+```sql
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0
+ THEN [e].[Value] * 2
+ ELSE 0
+END
+FROM [Entity] AS [e]
+```
+
+## Side Effect Detection
+
+The generator provides specific error reporting for side effects in block-bodied methods, helping you identify and fix issues quickly.
+
+### Detected Side Effects
+
+#### 1. Property Assignments (EFP0004 - Error)
+
+Property assignments modify state and are not allowed:
+
+```csharp
+[Projectable]
+public int Foo()
+{
+ Bar = 10; // ❌ Error: Assignment operation has side effects
+ return Bar;
+}
+```
+
+#### 2. Compound Assignments (EFP0004 - Error)
+
+Compound assignment operators like `+=`, `-=`, `*=`, etc. are not allowed:
+
+```csharp
+[Projectable]
+public int Foo()
+{
+ Bar += 10; // ❌ Error: Compound assignment operator '+=' has side effects
+ return Bar;
+}
+```
+
+#### 3. Increment/Decrement Operators (EFP0004 - Error)
+
+Pre and post increment/decrement operators are not allowed:
+
+```csharp
+[Projectable]
+public int Foo()
+{
+ var x = 5;
+ x++; // ❌ Error: Increment/decrement operator '++' has side effects
+ return x;
+}
+```
+
+#### 4. Non-Projectable Method Calls (EFP0005 - Warning)
+
+Calls to methods not marked with `[Projectable]` may have side effects:
+
+```csharp
+[Projectable]
+public int Foo()
+{
+ Console.WriteLine("test"); // ⚠️ Warning: Method call 'WriteLine' may have side effects
+ return Bar;
+}
+```
+
+### Diagnostic Codes
+
+- **EFP0003**: Unsupported statement in block-bodied method (Warning)
+- **EFP0004**: Statement with side effects in block-bodied method (Error)
+- **EFP0005**: Potential side effect in block-bodied method (Warning)
+
+### Error Message Improvements
+
+Instead of generic error messages, you now get precise, actionable feedback:
+
+**Before:**
+```
+warning EFP0003: Method 'Foo' contains an unsupported statement: Expression statements are not supported
+```
+
+**After:**
+```
+error EFP0004: Property assignment 'Bar' has side effects and cannot be used in projectable methods
+```
+
+The error message points to the exact line with the problematic code, making it much easier to identify and fix issues.
+
diff --git a/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md b/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md
index ef168b8..c1b0078 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md
+++ b/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md
@@ -3,3 +3,6 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------
EFP0002 | Design | Error |
+EFP0003 | Design | Warning |
+EFP0004 | Design | Error | Statement with side effects in block-bodied method
+EFP0005 | Design | Warning | Potential side effect in block-bodied method
diff --git a/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs b/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
new file mode 100644
index 0000000..55abd92
--- /dev/null
+++ b/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
@@ -0,0 +1,539 @@
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace EntityFrameworkCore.Projectables.Generator
+{
+ ///
+ /// Converts block-bodied methods to expression syntax that can be used in expression trees.
+ /// Only supports a subset of C# statements.
+ ///
+ public class BlockStatementConverter
+ {
+ private readonly SourceProductionContext _context;
+ private readonly ExpressionSyntaxRewriter _expressionRewriter;
+ private readonly Dictionary _localVariables = new();
+
+ public BlockStatementConverter(SourceProductionContext context, ExpressionSyntaxRewriter expressionRewriter)
+ {
+ _context = context;
+ _expressionRewriter = expressionRewriter;
+ }
+
+ ///
+ /// Attempts to convert a block statement into a single expression.
+ /// Returns null if the block contains unsupported statements.
+ ///
+ public ExpressionSyntax? TryConvertBlock(BlockSyntax block, string memberName)
+ {
+ if (block.Statements.Count == 0)
+ {
+ var diagnostic = Diagnostic.Create(
+ Diagnostics.UnsupportedStatementInBlockBody,
+ block.GetLocation(),
+ memberName,
+ "Block body must contain at least one statement"
+ );
+ _context.ReportDiagnostic(diagnostic);
+ return null;
+ }
+
+ // Try to convert the block statements into an expression
+ return TryConvertStatements(block.Statements.ToList(), memberName);
+ }
+
+ private ExpressionSyntax? TryConvertStatements(List statements, string memberName)
+ {
+ if (statements.Count == 0)
+ {
+ return null;
+ }
+
+ if (statements.Count == 1)
+ {
+ return TryConvertStatement(statements[0], memberName);
+ }
+
+ // Multiple statements - try to convert them into a chain of expressions
+ // This is done by converting local variable declarations and then the final return
+ var nonReturnStatements = statements.Take(statements.Count - 1).ToList();
+ var lastStatement = statements.Last();
+
+ // First, process any local variable declarations at the beginning
+ var localDeclStatements = new List();
+ var remainingStatements = new List();
+
+ foreach (var stmt in nonReturnStatements)
+ {
+ if (stmt is LocalDeclarationStatementSyntax localDecl)
+ {
+ localDeclStatements.Add(localDecl);
+ }
+ else
+ {
+ remainingStatements.Add(stmt);
+ }
+ }
+
+ // Process local variable declarations first
+ foreach (var localDecl in localDeclStatements)
+ {
+ if (!TryProcessLocalDeclaration(localDecl, memberName))
+ {
+ return null;
+ }
+ }
+
+ // Check if we have a pattern like multiple if statements without else followed by a final return:
+ // var x = ...; if (a) return 1; if (b) return 2; return 3;
+ // This can be converted to nested ternaries: a ? 1 : (b ? 2 : 3)
+ if (lastStatement is ReturnStatementSyntax finalReturn &&
+ remainingStatements.All(s => s is IfStatementSyntax { Else: null }))
+ {
+ // All remaining non-return statements are if statements without else
+ var ifStatements = remainingStatements.Cast().ToList();
+
+ // Start with the final return as the base expression
+ var elseBody = TryConvertReturnStatement(finalReturn, memberName);
+ if (elseBody == null)
+ {
+ return null;
+ }
+
+ // Build nested conditionals from right to left (last to first)
+ for (var i = ifStatements.Count - 1; i >= 0; i--)
+ {
+ var ifStmt = ifStatements[i];
+ var ifBody = TryConvertStatement(ifStmt.Statement, memberName);
+ if (ifBody == null)
+ {
+ return null;
+ }
+
+ // Rewrite the condition and replace any local variables
+ var condition = (ExpressionSyntax)_expressionRewriter.Visit(ifStmt.Condition);
+ condition = ReplaceLocalVariables(condition);
+
+ elseBody = SyntaxFactory.ConditionalExpression(condition, ifBody, elseBody);
+ }
+
+ return elseBody;
+ }
+
+ // If there are any remaining non-if statements, try to convert them individually
+ // This will provide better error messages for unsupported statements
+ if (remainingStatements.Count > 0)
+ {
+ // Try converting each remaining statement - this will provide specific error messages
+ foreach (var stmt in remainingStatements)
+ {
+ var converted = TryConvertStatement(stmt, memberName);
+ if (converted == null)
+ {
+ return null;
+ }
+ }
+
+ // If we got here but had non-if statements, they weren't properly handled
+ ReportUnsupportedStatement(remainingStatements[0], memberName,
+ "Only local variable declarations and if statements without else (with return) are supported before the final return statement");
+ return null;
+ }
+
+ // Convert the final statement (should be a return)
+ return TryConvertStatement(lastStatement, memberName);
+ }
+
+ private bool TryProcessLocalDeclaration(LocalDeclarationStatementSyntax localDecl, string memberName)
+ {
+ foreach (var variable in localDecl.Declaration.Variables)
+ {
+ if (variable.Initializer == null)
+ {
+ ReportUnsupportedStatement(localDecl, memberName, "Local variables must have an initializer");
+ return false;
+ }
+
+ var variableName = variable.Identifier.Text;
+
+ // Rewrite the initializer expression NOW while it's still in the tree
+ var rewrittenInitializer = (ExpressionSyntax)_expressionRewriter.Visit(variable.Initializer.Value);
+
+ // Also expand any previously defined local variables in this initializer
+ // This ensures transitive inlining (e.g., var a = 1; var b = a + 2; return b; -> 1 + 2)
+ rewrittenInitializer = ReplaceLocalVariables(rewrittenInitializer);
+
+ _localVariables[variableName] = rewrittenInitializer;
+ }
+
+ return true;
+ }
+
+ private ExpressionSyntax? TryConvertStatement(StatementSyntax statement, string memberName)
+ {
+ switch (statement)
+ {
+ case ReturnStatementSyntax returnStmt:
+ return TryConvertReturnStatement(returnStmt, memberName);
+
+ case IfStatementSyntax ifStmt:
+ return TryConvertIfStatement(ifStmt, memberName);
+
+ case SwitchStatementSyntax switchStmt:
+ return TryConvertSwitchStatement(switchStmt, memberName);
+
+ case BlockSyntax blockStmt:
+ // Prevent locals declared in nested blocks from leaking into outer scopes
+ var nestedLocal = blockStmt.DescendantNodes()
+ .OfType()
+ .FirstOrDefault();
+
+ if (nestedLocal is not null)
+ {
+ ReportUnsupportedStatement(nestedLocal, memberName, "Local declarations in nested blocks are not supported");
+ return null;
+ }
+
+ return TryConvertStatements(blockStmt.Statements.ToList(), memberName);
+
+ case ExpressionStatementSyntax exprStmt:
+ // Expression statements may contain side effects - analyze them
+ return AnalyzeExpressionStatement(exprStmt, memberName);
+
+ case LocalDeclarationStatementSyntax:
+ // Local declarations should be handled before the return statement
+ ReportUnsupportedStatement(statement, memberName, "Local declarations must appear before the return statement");
+ return null;
+
+ default:
+ ReportUnsupportedStatement(statement, memberName, $"Statement type '{statement.GetType().Name}' is not supported");
+ return null;
+ }
+ }
+
+ private ExpressionSyntax? TryConvertReturnStatement(ReturnStatementSyntax returnStmt, string memberName)
+ {
+ if (returnStmt.Expression == null)
+ {
+ ReportUnsupportedStatement(returnStmt, memberName, "Return statement must have an expression");
+ return null;
+ }
+
+ // First rewrite the return expression
+ var expression = (ExpressionSyntax)_expressionRewriter.Visit(returnStmt.Expression);
+
+ // Then replace any local variable references with their already-rewritten initializers
+ expression = ReplaceLocalVariables(expression);
+
+ return expression;
+ }
+
+ private ConditionalExpressionSyntax? TryConvertIfStatement(IfStatementSyntax ifStmt, string memberName)
+ {
+ // Convert if-else to conditional (ternary) expression
+ // First, rewrite the condition using the expression rewriter
+ var condition = (ExpressionSyntax)_expressionRewriter.Visit(ifStmt.Condition);
+
+ // Then replace any local variable references with their already-rewritten initializers
+ condition = ReplaceLocalVariables(condition);
+
+ var whenTrue = TryConvertStatement(ifStmt.Statement, memberName);
+ if (whenTrue == null)
+ {
+ return null;
+ }
+
+ ExpressionSyntax? whenFalse;
+ if (ifStmt.Else != null)
+ {
+ whenFalse = TryConvertStatement(ifStmt.Else.Statement, memberName);
+ if (whenFalse == null)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ // If there's no else clause, use a default literal
+ // This will be inferred to the correct type by the compiler
+ whenFalse = SyntaxFactory.LiteralExpression(
+ SyntaxKind.DefaultLiteralExpression,
+ SyntaxFactory.Token(SyntaxKind.DefaultKeyword)
+ );
+ }
+
+ // Create a conditional expression with the rewritten nodes
+ return SyntaxFactory.ConditionalExpression(
+ condition,
+ whenTrue,
+ whenFalse
+ );
+ }
+
+ private ExpressionSyntax? TryConvertSwitchStatement(SwitchStatementSyntax switchStmt, string memberName)
+ {
+ // Convert switch statement to nested conditional expressions
+ // Process sections in reverse order to build from the default case up
+
+ var switchExpression = (ExpressionSyntax)_expressionRewriter.Visit(switchStmt.Expression);
+ // Replace any local variable references in the switch expression
+ switchExpression = ReplaceLocalVariables(switchExpression);
+
+ ExpressionSyntax? currentExpression;
+
+ // Find default case first
+ SwitchSectionSyntax? defaultSection = null;
+ var nonDefaultSections = new List();
+
+ foreach (var section in switchStmt.Sections)
+ {
+ var hasDefault = section.Labels.Any(label => label is DefaultSwitchLabelSyntax);
+ if (hasDefault)
+ {
+ defaultSection = section;
+ }
+ else
+ {
+ nonDefaultSections.Add(section);
+ }
+ }
+
+ // Start with default case or null
+ if (defaultSection != null)
+ {
+ currentExpression = ConvertSwitchSection(defaultSection, memberName);
+ if (currentExpression == null)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ // No default case - use default literal
+ currentExpression = SyntaxFactory.LiteralExpression(
+ SyntaxKind.DefaultLiteralExpression,
+ SyntaxFactory.Token(SyntaxKind.DefaultKeyword)
+ );
+ }
+
+ // Process non-default sections in reverse order
+ for (var i = nonDefaultSections.Count - 1; i >= 0; i--)
+ {
+ var section = nonDefaultSections[i];
+ var sectionExpression = ConvertSwitchSection(section, memberName);
+ if (sectionExpression == null)
+ {
+ return null;
+ }
+
+ // Build condition for all labels in this section (OR'd together)
+ ExpressionSyntax? condition = null;
+ foreach (var label in section.Labels)
+ {
+ if (label is CaseSwitchLabelSyntax caseLabel)
+ {
+ // Rewrite and replace locals in case label value
+ var caseLabelValue = (ExpressionSyntax)_expressionRewriter.Visit(caseLabel.Value);
+ caseLabelValue = ReplaceLocalVariables(caseLabelValue);
+
+ var labelCondition = SyntaxFactory.BinaryExpression(
+ SyntaxKind.EqualsExpression,
+ switchExpression,
+ caseLabelValue
+ );
+
+ condition = condition == null
+ ? labelCondition
+ : SyntaxFactory.BinaryExpression(
+ SyntaxKind.LogicalOrExpression,
+ condition,
+ labelCondition
+ );
+ }
+ else if (label is not DefaultSwitchLabelSyntax)
+ {
+ // Unsupported label type (e.g., pattern-based switch in older syntax)
+ ReportUnsupportedStatement(switchStmt, memberName,
+ $"Switch label type '{label.GetType().Name}' is not supported. Use case labels or switch expressions instead.");
+ return null;
+ }
+ }
+
+ if (condition != null)
+ {
+ currentExpression = SyntaxFactory.ConditionalExpression(
+ condition,
+ sectionExpression,
+ currentExpression
+ );
+ }
+ }
+
+ return currentExpression;
+ }
+
+ private ExpressionSyntax? ConvertSwitchSection(SwitchSectionSyntax section, string memberName)
+ {
+ // Convert the statements in the switch section
+ // Most switch sections end with break, return, or throw
+ var statements = section.Statements.ToList();
+
+ // Remove trailing break statements as they're not needed in expressions
+ if (statements.Count > 0 && statements.Last() is BreakStatementSyntax)
+ {
+ statements = statements.Take(statements.Count - 1).ToList();
+ }
+
+ if (statements.Count != 0)
+ {
+ return TryConvertStatements(statements, memberName);
+ }
+
+ // Use the section's first label location for error reporting
+ var firstLabel = section.Labels.FirstOrDefault();
+ if (firstLabel == null)
+ {
+ return null;
+ }
+
+ var diagnostic = Diagnostic.Create(
+ Diagnostics.UnsupportedStatementInBlockBody,
+ firstLabel.GetLocation(),
+ memberName,
+ "Switch section must have at least one statement"
+ );
+ _context.ReportDiagnostic(diagnostic);
+ return null;
+
+ }
+
+ private ExpressionSyntax ReplaceLocalVariables(ExpressionSyntax expression)
+ {
+ // Use a rewriter to replace local variable references with their initializer expressions
+ var rewriter = new LocalVariableReplacer(_localVariables);
+ return (ExpressionSyntax)rewriter.Visit(expression);
+ }
+
+ private ExpressionSyntax? AnalyzeExpressionStatement(ExpressionStatementSyntax exprStmt, string memberName)
+ {
+ var expression = exprStmt.Expression;
+
+ // Check for specific side effects
+ switch (expression)
+ {
+ case AssignmentExpressionSyntax assignment:
+ ReportSideEffect(assignment, GetAssignmentErrorMessage(assignment));
+ return null;
+
+ case PostfixUnaryExpressionSyntax postfix when
+ postfix.IsKind(SyntaxKind.PostIncrementExpression) ||
+ postfix.IsKind(SyntaxKind.PostDecrementExpression):
+ ReportSideEffect(postfix, $"Increment/decrement operator '{postfix.OperatorToken.Text}' has side effects and cannot be used in projectable methods");
+ return null;
+
+ case PrefixUnaryExpressionSyntax prefix when
+ prefix.IsKind(SyntaxKind.PreIncrementExpression) ||
+ prefix.IsKind(SyntaxKind.PreDecrementExpression):
+ ReportSideEffect(prefix, $"Increment/decrement operator '{prefix.OperatorToken.Text}' has side effects and cannot be used in projectable methods");
+ return null;
+
+ case InvocationExpressionSyntax invocation:
+ // Check if this is a potentially impure method call
+ var symbolInfo = _expressionRewriter.GetSemanticModel().GetSymbolInfo(invocation);
+ if (symbolInfo.Symbol is IMethodSymbol methodSymbol)
+ {
+ // Check if method has [Projectable] attribute - those are safe
+ var hasProjectableAttr = methodSymbol.GetAttributes()
+ .Any(attr => attr.AttributeClass?.Name == "ProjectableAttribute");
+
+ if (!hasProjectableAttr)
+ {
+ ReportPotentialSideEffect(invocation,
+ $"Method call '{methodSymbol.Name}' may have side effects. Only calls to methods marked with [Projectable] are guaranteed to be safe in projectable methods");
+ return null;
+ }
+ }
+ break;
+ }
+
+ // If we got here, it's an expression statement we don't support
+ ReportUnsupportedStatement(exprStmt, memberName, "Expression statements are not supported in projectable methods");
+ return null;
+ }
+
+ private string GetAssignmentErrorMessage(AssignmentExpressionSyntax assignment)
+ {
+ var operatorText = assignment.OperatorToken.Text;
+
+ if (assignment.IsKind(SyntaxKind.SimpleAssignmentExpression))
+ {
+ if (assignment.Left is MemberAccessExpressionSyntax memberAccess)
+ {
+ return $"Property assignment '{memberAccess.Name}' has side effects and cannot be used in projectable methods";
+ }
+ return $"Assignment operation has side effects and cannot be used in projectable methods";
+ }
+ else
+ {
+ // Compound assignment like +=, -=, etc.
+ return $"Compound assignment operator '{operatorText}' has side effects and cannot be used in projectable methods";
+ }
+ }
+
+ private void ReportSideEffect(SyntaxNode node, string message)
+ {
+ var diagnostic = Diagnostic.Create(
+ Diagnostics.SideEffectInBlockBody,
+ node.GetLocation(),
+ message
+ );
+ _context.ReportDiagnostic(diagnostic);
+ }
+
+ private void ReportPotentialSideEffect(SyntaxNode node, string message)
+ {
+ var diagnostic = Diagnostic.Create(
+ Diagnostics.PotentialSideEffectInBlockBody,
+ node.GetLocation(),
+ message
+ );
+ _context.ReportDiagnostic(diagnostic);
+ }
+
+ private void ReportUnsupportedStatement(StatementSyntax statement, string memberName, string reason)
+ {
+ var diagnostic = Diagnostic.Create(
+ Diagnostics.UnsupportedStatementInBlockBody,
+ statement.GetLocation(),
+ memberName,
+ reason
+ );
+ _context.ReportDiagnostic(diagnostic);
+ }
+
+
+ private class LocalVariableReplacer : CSharpSyntaxRewriter
+ {
+ private readonly Dictionary _localVariables;
+
+ public LocalVariableReplacer(Dictionary localVariables)
+ {
+ _localVariables = localVariables;
+ }
+
+ public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
+ {
+ var identifier = node.Identifier.Text;
+ if (_localVariables.TryGetValue(identifier, out var replacement))
+ {
+ // Replace the identifier with the expression it was initialized with
+ return replacement.WithTriviaFrom(node);
+ }
+
+ return base.VisitIdentifierName(node);
+ }
+ }
+ }
+}
diff --git a/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs b/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs
index 18f87c1..6bcfaf1 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs
+++ b/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs
@@ -25,5 +25,29 @@ public static class Diagnostics
DiagnosticSeverity.Error,
isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor UnsupportedStatementInBlockBody = new DiagnosticDescriptor(
+ id: "EFP0003",
+ title: "Unsupported statement in block-bodied method",
+ messageFormat: "Method '{0}' contains an unsupported statement: {1}",
+ category: "Design",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
+
+ public static readonly DiagnosticDescriptor SideEffectInBlockBody = new DiagnosticDescriptor(
+ id: "EFP0004",
+ title: "Statement with side effects in block-bodied method",
+ messageFormat: "{0}",
+ category: "Design",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
+
+ public static readonly DiagnosticDescriptor PotentialSideEffectInBlockBody = new DiagnosticDescriptor(
+ id: "EFP0005",
+ title: "Potential side effect in block-bodied method",
+ messageFormat: "{0}",
+ category: "Design",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
+
}
}
diff --git a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
index f51c8f6..f953701 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
+++ b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
@@ -1,4 +1,4 @@
-using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;
@@ -26,6 +26,8 @@ public ExpressionSyntaxRewriter(INamedTypeSymbol targetTypeSymbol, NullCondition
_extensionParameterName = extensionParameterName;
}
+ public SemanticModel GetSemanticModel() => _semanticModel;
+
private SyntaxNode? VisitThisBaseExpression(CSharpSyntaxNode node)
{
// Swap out the use of this and base to @this and keep leading and trailing trivias
@@ -386,8 +388,47 @@ private ExpressionSyntax CreateMethodCallOnEnumValue(IMethodSymbol methodSymbol,
continue;
}
+ // Handle relational patterns (<=, <, >=, >)
+ if (arm.Pattern is RelationalPatternSyntax relational)
+ {
+ // Map the pattern operator token to a binary expression kind
+ var binaryKind = relational.OperatorToken.Kind() switch
+ {
+ SyntaxKind.LessThanToken => SyntaxKind.LessThanExpression,
+ SyntaxKind.LessThanEqualsToken => SyntaxKind.LessThanOrEqualExpression,
+ SyntaxKind.GreaterThanToken => SyntaxKind.GreaterThanExpression,
+ SyntaxKind.GreaterThanEqualsToken => SyntaxKind.GreaterThanOrEqualExpression,
+ _ => throw new InvalidOperationException(
+ $"Unsupported relational operator in switch expression: {relational.OperatorToken.Kind()}")
+ };
+
+ var condition = SyntaxFactory.BinaryExpression(
+ binaryKind,
+ (ExpressionSyntax)Visit(node.GoverningExpression),
+ (ExpressionSyntax)Visit(relational.Expression)
+ );
+
+ // Add the when clause as a AND expression
+ if (arm.WhenClause != null)
+ {
+ condition = SyntaxFactory.BinaryExpression(
+ SyntaxKind.LogicalAndExpression,
+ condition,
+ (ExpressionSyntax)Visit(arm.WhenClause.Condition)
+ );
+ }
+
+ currentExpression = SyntaxFactory.ConditionalExpression(
+ condition,
+ armExpression,
+ currentExpression
+ );
+
+ continue;
+ }
+
throw new InvalidOperationException(
- $"Switch expressions rewriting supports only constant values and declaration patterns (Type var). " +
+ $"Switch expressions rewriting supports constant values, relational patterns (<=, <, >=, >), and declaration patterns (Type var). " +
$"Unsupported pattern: {arm.Pattern.GetType().Name}"
);
}
diff --git a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs
index 8a84310..5006081 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs
+++ b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs
@@ -120,7 +120,7 @@ x is IPropertySymbol xProperty &&
return false;
}
else if (x is MethodDeclarationSyntax xMethod &&
- xMethod.ExpressionBody is not null)
+ (xMethod.ExpressionBody is not null || xMethod.Body is not null))
{
return true;
}
@@ -302,7 +302,28 @@ x is IPropertySymbol xProperty &&
if (memberBody is MethodDeclarationSyntax methodDeclarationSyntax)
{
- if (methodDeclarationSyntax.ExpressionBody is null)
+ ExpressionSyntax? bodyExpression = null;
+
+ if (methodDeclarationSyntax.ExpressionBody is not null)
+ {
+ // Expression-bodied method (e.g., int Foo() => 1;)
+ bodyExpression = methodDeclarationSyntax.ExpressionBody.Expression;
+ }
+ else if (methodDeclarationSyntax.Body is not null)
+ {
+ // Block-bodied method (e.g., int Foo() { return 1; })
+ var blockConverter = new BlockStatementConverter(context, expressionSyntaxRewriter);
+ bodyExpression = blockConverter.TryConvertBlock(methodDeclarationSyntax.Body, memberSymbol.Name);
+
+ if (bodyExpression is null)
+ {
+ // Diagnostics already reported by BlockStatementConverter
+ return null;
+ }
+
+ // The expression has already been rewritten by BlockStatementConverter, so we don't rewrite it again
+ }
+ else
{
var diagnostic = Diagnostic.Create(Diagnostics.RequiresExpressionBodyDefinition, methodDeclarationSyntax.GetLocation(), memberSymbol.Name);
context.ReportDiagnostic(diagnostic);
@@ -312,7 +333,10 @@ x is IPropertySymbol xProperty &&
var returnType = declarationSyntaxRewriter.Visit(methodDeclarationSyntax.ReturnType);
descriptor.ReturnTypeName = returnType.ToString();
- descriptor.ExpressionBody = (ExpressionSyntax)expressionSyntaxRewriter.Visit(methodDeclarationSyntax.ExpressionBody.Expression);
+ // Only rewrite expression-bodied methods, block-bodied methods are already rewritten
+ descriptor.ExpressionBody = methodDeclarationSyntax.ExpressionBody is not null
+ ? (ExpressionSyntax)expressionSyntaxRewriter.Visit(bodyExpression)
+ : bodyExpression;
foreach (var additionalParameter in ((ParameterListSyntax)declarationSyntaxRewriter.Visit(methodDeclarationSyntax.ParameterList)).Parameters)
{
descriptor.ParametersList = descriptor.ParametersList.AddParameters(additionalParameter);
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..3eaf767
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..3eaf767
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..3eaf767
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..dab6bd4
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT 15
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..dab6bd4
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT 15
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..dab6bd4
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT 15
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..e5b6efb
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..e5b6efb
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..e5b6efb
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..a19f725
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2
+ ELSE 0
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..a19f725
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2
+ ELSE 0
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt
new file mode 100644
index 0000000..a19f725
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2
+ ELSE 0
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..ba1f2c1
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT CAST(LEN([e].[Name]) AS int)
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..ba1f2c1
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT CAST(LEN([e].[Name]) AS int)
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..ba1f2c1
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT CAST(LEN([e].[Name]) AS int)
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..4d0592a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active'
+ ELSE N'Active'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..4d0592a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active'
+ ELSE N'Active'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..4d0592a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active'
+ ELSE N'Active'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt
new file mode 100644
index 0000000..a29be77
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0
+ WHEN [e].[Value] < 0 THEN 0
+ ELSE [e].[Value] * 2
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt
new file mode 100644
index 0000000..a29be77
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0
+ WHEN [e].[Value] < 0 THEN 0
+ ELSE [e].[Value] * 2
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt
new file mode 100644
index 0000000..a29be77
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0
+ WHEN [e].[Value] < 0 THEN 0
+ ELSE [e].[Value] * 2
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt
new file mode 100644
index 0000000..26ac26b
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt
new file mode 100644
index 0000000..26ac26b
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt
new file mode 100644
index 0000000..26ac26b
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt
new file mode 100644
index 0000000..0c5fe1e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt
@@ -0,0 +1,4 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt
new file mode 100644
index 0000000..0c5fe1e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt
@@ -0,0 +1,4 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt
new file mode 100644
index 0000000..7e3c8c6
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2
+ ELSE NULL
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt
new file mode 100644
index 0000000..eec38d9
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt
new file mode 100644
index 0000000..eec38d9
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt
new file mode 100644
index 0000000..eec38d9
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9689484
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 5
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9689484
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 5
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt
new file mode 100644
index 0000000..9689484
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 5
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt
new file mode 100644
index 0000000..257f6f0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[Value] > 50 THEN N'Active Medium'
+ ELSE N'Active Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt
new file mode 100644
index 0000000..257f6f0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[Value] > 50 THEN N'Active Medium'
+ ELSE N'Active Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt
new file mode 100644
index 0000000..257f6f0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[Value] > 50 THEN N'Active Medium'
+ ELSE N'Active Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt
new file mode 100644
index 0000000..1ae6355
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Very High'
+ WHEN [e].[Value] > 50 THEN N'High'
+ WHEN [e].[Value] > 10 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt
new file mode 100644
index 0000000..1ae6355
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Very High'
+ WHEN [e].[Value] > 50 THEN N'High'
+ WHEN [e].[Value] > 10 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt
new file mode 100644
index 0000000..1ae6355
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Very High'
+ WHEN [e].[Value] > 50 THEN N'High'
+ WHEN [e].[Value] > 10 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..4a903b0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..4a903b0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt
new file mode 100644
index 0000000..4a903b0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt
new file mode 100644
index 0000000..6973619
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium'
+ WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt
new file mode 100644
index 0000000..6973619
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium'
+ WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt
new file mode 100644
index 0000000..6973619
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High'
+ WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium'
+ WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..5f5a209
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] = 1 THEN N'Active One'
+ WHEN [e].[Value] = 2 THEN N'Active Two'
+ ELSE N'Active Other'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..5f5a209
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] = 1 THEN N'Active One'
+ WHEN [e].[Value] = 2 THEN N'Active Two'
+ ELSE N'Active Other'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..5f5a209
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] = 1 THEN N'Active One'
+ WHEN [e].[Value] = 2 THEN N'Active Two'
+ ELSE N'Active Other'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..9d42002
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt
@@ -0,0 +1,6 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ WHEN [e].[Value] > 50 THEN N'Medium'
+ ELSE N'Low'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..52f2a3e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT COALESCE([e].[Name], N'Unknown')
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..52f2a3e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT COALESCE([e].[Name], N'Unknown')
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..52f2a3e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT COALESCE([e].[Name], N'Unknown')
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt
new file mode 100644
index 0000000..06a56fa
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt
new file mode 100644
index 0000000..06a56fa
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt
new file mode 100644
index 0000000..06a56fa
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt
new file mode 100644
index 0000000..6efc8d2
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt
new file mode 100644
index 0000000..6efc8d2
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt
new file mode 100644
index 0000000..6efc8d2
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt
@@ -0,0 +1,2 @@
+SELECT 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..e6bf43e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value]
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..e6bf43e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value]
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..e6bf43e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value]
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt
new file mode 100644
index 0000000..727148f
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] <= 2 THEN N'Low'
+ WHEN [e].[Value] <= 5 THEN N'Medium'
+ WHEN [e].[Value] <= 8 THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt
new file mode 100644
index 0000000..727148f
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] <= 2 THEN N'Low'
+ WHEN [e].[Value] <= 5 THEN N'Medium'
+ WHEN [e].[Value] <= 8 THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt
new file mode 100644
index 0000000..727148f
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] <= 2 THEN N'Low'
+ WHEN [e].[Value] <= 5 THEN N'Medium'
+ WHEN [e].[Value] <= 8 THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt
new file mode 100644
index 0000000..9ed7fa8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 THEN N'One'
+ WHEN [e].[Value] = 2 THEN N'Two'
+ WHEN [e].[Value] = 3 THEN N'Three'
+ ELSE N'Many'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt
new file mode 100644
index 0000000..9c8b78e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] IN (1, 2) THEN N'Low'
+ WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium'
+ WHEN [e].[Value] IN (6, 7, 8) THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt
new file mode 100644
index 0000000..9c8b78e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] IN (1, 2) THEN N'Low'
+ WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium'
+ WHEN [e].[Value] IN (6, 7, 8) THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt
new file mode 100644
index 0000000..9c8b78e
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] IN (1, 2) THEN N'Low'
+ WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium'
+ WHEN [e].[Value] IN (6, 7, 8) THEN N'High'
+ ELSE N'Critical'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..f2343d3
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One'
+ WHEN [e].[Value] = 1 THEN N'Inactive One'
+ WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..f2343d3
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One'
+ WHEN [e].[Value] = 1 THEN N'Inactive One'
+ WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..f2343d3
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt
@@ -0,0 +1,7 @@
+SELECT CASE
+ WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One'
+ WHEN [e].[Value] = 1 THEN N'Inactive One'
+ WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High'
+ ELSE N'Other'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt
new file mode 100644
index 0000000..f3f5c43
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active'
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs
new file mode 100644
index 0000000..9622f34
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs
@@ -0,0 +1,672 @@
+using EntityFrameworkCore.Projectables.FunctionalTests.Helpers;
+using Microsoft.EntityFrameworkCore;
+using System.Linq;
+using System.Threading.Tasks;
+using VerifyXunit;
+using Xunit;
+
+namespace EntityFrameworkCore.Projectables.FunctionalTests.BlockBodiedMethods
+{
+ [UsesVerify]
+ public class BlockBodiedMethodTests
+ {
+ public record Entity
+ {
+ public int Id { get; set; }
+ public int Value { get; set; }
+ public bool IsActive { get; set; }
+ public string? Name { get; set; }
+ }
+
+ [Fact]
+ public Task SimpleReturn_IsTranslatedToSql()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetConstant());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task ReturnWithPropertyAccess_IsTranslatedToSql()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValuePlusTen());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task IfElseStatement_IsTranslatedToTernary()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetCategory());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task NestedIfElse_IsTranslatedToNestedTernary()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetLevel());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task LocalVariable_IsInlined()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.CalculateDouble());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task ComplexConditional_IsTranslatedCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetAdjustedValue());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockMethodWithParameters_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.Add(5, 10));
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task IfWithoutElse_UsesDefault()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetPremiumIfActive());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task IfWithoutElse_WithFallbackReturn()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetStatus());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task SwitchStatement_Simple()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValueLabel());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task SwitchStatement_WithMultipleCases()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetPriority());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task MultipleEarlyReturns_ConvertedToNestedTernaries()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValueCategory());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task NullCoalescing_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetNameOrDefault());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task ConditionalAccess_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetNameLength());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task SwitchExpression_Simple()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValueLabelModern());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task SwitchExpression_WithDiscard()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetPriorityModern());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task MultipleLocalVariables_AreInlinedCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.CalculateComplex());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task NestedConditionals_WithLogicalOperators()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetComplexCategory());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task GuardClause_WithEarlyReturn()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetGuardedValue());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task NestedSwitchInIf_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetCombinedLogic());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task TernaryExpression_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValueUsingTernary());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task NestedTernary_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetNestedTernary());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task MixedIfAndSwitch_WithMultiplePatterns()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetComplexMix());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task SwitchWithWhenClause_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetValueWithCondition());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task LocalVariableReuse_IsInlinedMultipleTimes()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.CalculateWithReuse());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BooleanReturn_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.IsHighValue());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task ConditionalWithNegation_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetInactiveStatus());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task StringInterpolation_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.GetFormattedValue());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task ArithmeticInReturn_WorksCorrectly()
+ {
+ using var dbContext = new SampleDbContext();
+
+ var query = dbContext.Set()
+ .Select(x => x.CalculatePercentage());
+
+ return Verifier.Verify(query.ToQueryString());
+ }
+ }
+
+ public static class EntityExtensions
+ {
+ [Projectable]
+ public static int GetConstant(this BlockBodiedMethodTests.Entity entity)
+ {
+ return 42;
+ }
+
+ [Projectable]
+ public static int GetValuePlusTen(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Value + 10;
+ }
+
+ [Projectable]
+ public static string GetCategory(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.Value > 100)
+ {
+ return "High";
+ }
+ else
+ {
+ return "Low";
+ }
+ }
+
+ [Projectable]
+ public static string GetLevel(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.Value > 100)
+ {
+ return "High";
+ }
+ else if (entity.Value > 50)
+ {
+ return "Medium";
+ }
+ else
+ {
+ return "Low";
+ }
+ }
+
+ [Projectable]
+ public static int CalculateDouble(this BlockBodiedMethodTests.Entity entity)
+ {
+ var doubled = entity.Value * 2;
+ return doubled + 5;
+ }
+
+ [Projectable]
+ public static int GetAdjustedValue(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive && entity.Value > 0)
+ {
+ return entity.Value * 2;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ [Projectable]
+ public static int Add(this BlockBodiedMethodTests.Entity entity, int a, int b)
+ {
+ return a + b;
+ }
+
+ [Projectable]
+ public static int? GetPremiumIfActive(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive)
+ {
+ return entity.Value * 2;
+ }
+ return null;
+ }
+
+ [Projectable]
+ public static string GetStatus(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive)
+ {
+ return "Active";
+ }
+ return "Inactive";
+ }
+
+ [Projectable]
+ public static string GetValueLabel(this BlockBodiedMethodTests.Entity entity)
+ {
+ switch (entity.Value)
+ {
+ case 1:
+ return "One";
+ case 2:
+ return "Two";
+ case 3:
+ return "Three";
+ default:
+ return "Many";
+ }
+ }
+
+ [Projectable]
+ public static string GetPriority(this BlockBodiedMethodTests.Entity entity)
+ {
+ switch (entity.Value)
+ {
+ case 1:
+ case 2:
+ return "Low";
+ case 3:
+ case 4:
+ case 5:
+ return "Medium";
+ case 6:
+ case 7:
+ case 8:
+ return "High";
+ default:
+ return "Critical";
+ }
+ }
+
+ [Projectable]
+ public static string GetValueCategory(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.Value > 100)
+ {
+ return "Very High";
+ }
+
+ if (entity.Value > 50)
+ {
+ return "High";
+ }
+
+ if (entity.Value > 10)
+ {
+ return "Medium";
+ }
+
+ return "Low";
+ }
+
+ [Projectable]
+ public static string GetNameOrDefault(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Name ?? "Unknown";
+ }
+
+ [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)]
+ public static int? GetNameLength(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Name?.Length;
+ }
+
+ [Projectable]
+ public static string GetValueLabelModern(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Value switch
+ {
+ 1 => "One",
+ 2 => "Two",
+ 3 => "Three",
+ _ => "Many"
+ };
+ }
+
+ [Projectable]
+ public static string GetPriorityModern(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Value switch
+ {
+ <= 2 => "Low",
+ <= 5 => "Medium",
+ <= 8 => "High",
+ _ => "Critical"
+ };
+ }
+
+ [Projectable]
+ public static int CalculateComplex(this BlockBodiedMethodTests.Entity entity)
+ {
+ var doubled = entity.Value * 2;
+ var tripled = entity.Value * 3;
+ var sum = doubled + tripled;
+ return sum + 10;
+ }
+
+ [Projectable]
+ public static string GetComplexCategory(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive && entity.Value > 100)
+ {
+ return "Active High";
+ }
+
+ if (entity.IsActive || entity.Value > 50)
+ {
+ return "Active or Medium";
+ }
+
+ if (!entity.IsActive && entity.Value <= 10)
+ {
+ return "Inactive Low";
+ }
+
+ return "Other";
+ }
+
+ [Projectable]
+ public static int GetGuardedValue(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (!entity.IsActive)
+ {
+ return 0;
+ }
+
+ if (entity.Value < 0)
+ {
+ return 0;
+ }
+
+ return entity.Value * 2;
+ }
+
+ [Projectable]
+ public static string GetCombinedLogic(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive)
+ {
+ switch (entity.Value)
+ {
+ case 1:
+ return "Active One";
+ case 2:
+ return "Active Two";
+ default:
+ return "Active Other";
+ }
+ }
+
+ return "Inactive";
+ }
+
+ [Projectable]
+ public static string GetValueUsingTernary(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.IsActive ? "Active" : "Inactive";
+ }
+
+ [Projectable]
+ public static string GetNestedTernary(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Value > 100 ? "High" : entity.Value > 50 ? "Medium" : "Low";
+ }
+
+ [Projectable]
+ public static string GetComplexMix(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.IsActive)
+ {
+ return entity.Value switch
+ {
+ > 100 => "Active High",
+ > 50 => "Active Medium",
+ _ => "Active Low"
+ };
+ }
+
+ return "Inactive";
+ }
+
+ [Projectable]
+ public static string GetValueWithCondition(this BlockBodiedMethodTests.Entity entity)
+ {
+ return entity.Value switch
+ {
+ 1 when entity.IsActive => "Active One",
+ 1 => "Inactive One",
+ > 10 when entity.IsActive => "Active High",
+ _ => "Other"
+ };
+ }
+
+ [Projectable]
+ public static int CalculateWithReuse(this BlockBodiedMethodTests.Entity entity)
+ {
+ var doubled = entity.Value * 2;
+ return doubled + doubled;
+ }
+
+ [Projectable]
+ public static bool IsHighValue(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (entity.Value > 100)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ [Projectable]
+ public static string GetInactiveStatus(this BlockBodiedMethodTests.Entity entity)
+ {
+ if (!entity.IsActive)
+ {
+ return "Not Active";
+ }
+ else
+ {
+ return "Active";
+ }
+ }
+
+ [Projectable]
+ public static string GetFormattedValue(this BlockBodiedMethodTests.Entity entity)
+ {
+ return $"Value: {entity.Value}";
+ }
+
+ [Projectable]
+ public static double CalculatePercentage(this BlockBodiedMethodTests.Entity entity)
+ {
+ return (double)entity.Value / 100.0 * 50.0;
+ }
+ }
+}
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs
new file mode 100644
index 0000000..c09237b
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs
@@ -0,0 +1,273 @@
+using EntityFrameworkCore.Projectables.FunctionalTests.Helpers;
+using Microsoft.EntityFrameworkCore;
+using System.Linq;
+using System.Threading.Tasks;
+using VerifyXunit;
+using Xunit;
+
+namespace EntityFrameworkCore.Projectables.FunctionalTests.BlockBodiedMethods
+{
+ ///
+ /// Tests for calling projectable methods from within block-bodied methods
+ ///
+ [UsesVerify]
+ public class BlockBodyProjectableCallTests
+ {
+ public record Entity
+ {
+ public int Id { get; set; }
+ public int Value { get; set; }
+ public bool IsActive { get; set; }
+ public string? Name { get; set; }
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_Simple()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetAdjustedWithConstant());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InReturn()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetDoubledValue());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InCondition()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetCategoryBasedOnAdjusted());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_Multiple()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.CombineProjectableMethods());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InSwitch()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetLabelBasedOnCategory());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InSwitchExpression()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetDescriptionByLevel());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_WithLocalVariable()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.CalculateUsingProjectable());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_Nested()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetNestedProjectableCall());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InEarlyReturn()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetStatusWithProjectableCheck());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InTernary()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.GetConditionalProjectable());
+ return Verifier.Verify(query.ToQueryString());
+ }
+
+ [Fact]
+ public Task BlockBodyCallingProjectableMethod_InLogicalExpression()
+ {
+ using var dbContext = new SampleDbContext();
+ var query = dbContext.Set()
+ .Select(x => x.IsComplexCondition());
+ return Verifier.Verify(query.ToQueryString());
+ }
+ }
+
+ public static class ProjectableCallExtensions
+ {
+ // Base projectable methods (helper methods)
+ [Projectable]
+ public static int GetConstant(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return 42;
+ }
+
+ [Projectable]
+ public static int GetDoubled(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.Value * 2;
+ }
+
+ [Projectable]
+ public static string GetCategory(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ if (entity.Value > 100)
+ return "High";
+ else
+ return "Low";
+ }
+
+ [Projectable]
+ public static string GetLevel(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ if (entity.Value > 100) return "Level3";
+ if (entity.Value > 50) return "Level2";
+ return "Level1";
+ }
+
+ [Projectable]
+ public static bool IsHighValue(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.Value > 100;
+ }
+
+ // Block-bodied methods calling projectable methods
+
+ [Projectable]
+ public static int GetAdjustedWithConstant(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.Value + entity.GetConstant();
+ }
+
+ [Projectable]
+ public static int GetDoubledValue(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ var doubled = entity.GetDoubled();
+ return doubled;
+ }
+
+ [Projectable]
+ public static string GetCategoryBasedOnAdjusted(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ if (entity.GetDoubled() > 200)
+ {
+ return "Very High";
+ }
+ else
+ {
+ return "Normal";
+ }
+ }
+
+ [Projectable]
+ public static int CombineProjectableMethods(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.GetDoubled() + entity.GetConstant();
+ }
+
+ [Projectable]
+ public static string GetLabelBasedOnCategory(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ switch (entity.GetCategory())
+ {
+ case "High":
+ return "Premium";
+ case "Low":
+ return "Standard";
+ default:
+ return "Unknown";
+ }
+ }
+
+ [Projectable]
+ public static string GetDescriptionByLevel(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.GetLevel() switch
+ {
+ "Level3" => "Expert",
+ "Level2" => "Intermediate",
+ "Level1" => "Beginner",
+ _ => "Unknown"
+ };
+ }
+
+ [Projectable]
+ public static int CalculateUsingProjectable(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ var doubled = entity.GetDoubled();
+ var withConstant = doubled + entity.GetConstant();
+ return withConstant * 2;
+ }
+
+ [Projectable]
+ public static int GetNestedProjectableCall(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.GetAdjustedWithConstant() + 10;
+ }
+
+ [Projectable]
+ public static string GetStatusWithProjectableCheck(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ if (entity.IsHighValue())
+ return "Premium";
+
+ if (entity.GetCategory() == "High")
+ return "Standard High";
+
+ return "Normal";
+ }
+
+ [Projectable]
+ public static string GetConditionalProjectable(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.IsActive ? entity.GetCategory() : "Inactive";
+ }
+
+ [Projectable]
+ public static string GetChainedResult(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ var doubled = entity.GetDoubled();
+
+ if (doubled > 200)
+ {
+ return entity.GetCategory() + " Priority";
+ }
+
+ return entity.GetLevel();
+ }
+
+ [Projectable]
+ public static bool IsComplexCondition(this BlockBodyProjectableCallTests.Entity entity)
+ {
+ return entity.IsActive && entity.IsHighValue() || entity.GetDoubled() > 150;
+ }
+ }
+}
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt
new file mode 100644
index 0000000..478d0ba
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] * 2 > 200 THEN N'Very High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt
new file mode 100644
index 0000000..478d0ba
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] * 2 > 200 THEN N'Very High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt
new file mode 100644
index 0000000..478d0ba
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN [e].[Value] * 2 > 200 THEN N'Very High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt
new file mode 100644
index 0000000..bd650a0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Standard High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt
new file mode 100644
index 0000000..bd650a0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Standard High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt
new file mode 100644
index 0000000..bd650a0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt
@@ -0,0 +1,9 @@
+SELECT CASE
+ WHEN [e].[Value] > 100 THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Standard High'
+ ELSE N'Normal'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt
new file mode 100644
index 0000000..de3373a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt
new file mode 100644
index 0000000..de3373a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt
new file mode 100644
index 0000000..de3373a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt
@@ -0,0 +1,5 @@
+SELECT CASE
+ WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt
new file mode 100644
index 0000000..dea1914
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt
new file mode 100644
index 0000000..dea1914
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt
new file mode 100644
index 0000000..dea1914
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt
new file mode 100644
index 0000000..927c6ff
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt
@@ -0,0 +1,12 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'Low' THEN N'Standard'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt
new file mode 100644
index 0000000..927c6ff
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt
@@ -0,0 +1,12 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'Low' THEN N'Standard'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt
new file mode 100644
index 0000000..927c6ff
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt
@@ -0,0 +1,12 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'High' THEN N'Premium'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END = N'Low' THEN N'Standard'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt
new file mode 100644
index 0000000..409a445
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt
@@ -0,0 +1,19 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level3' THEN N'Expert'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level2' THEN N'Intermediate'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level1' THEN N'Beginner'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt
new file mode 100644
index 0000000..409a445
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt
@@ -0,0 +1,19 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level3' THEN N'Expert'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level2' THEN N'Intermediate'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level1' THEN N'Beginner'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt
new file mode 100644
index 0000000..409a445
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt
@@ -0,0 +1,19 @@
+SELECT CASE
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level3' THEN N'Expert'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level2' THEN N'Intermediate'
+ WHEN CASE
+ WHEN [e].[Value] > 100 THEN N'Level3'
+ WHEN [e].[Value] > 50 THEN N'Level2'
+ ELSE N'Level1'
+ END = N'Level1' THEN N'Beginner'
+ ELSE N'Unknown'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt
new file mode 100644
index 0000000..ad971d0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt
@@ -0,0 +1,8 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt
new file mode 100644
index 0000000..ad971d0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt
@@ -0,0 +1,8 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt
new file mode 100644
index 0000000..ad971d0
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt
@@ -0,0 +1,8 @@
+SELECT CASE
+ WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE
+ WHEN [e].[Value] > 100 THEN N'High'
+ ELSE N'Low'
+ END
+ ELSE N'Inactive'
+END
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt
new file mode 100644
index 0000000..69eb4b8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt
new file mode 100644
index 0000000..69eb4b8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt
new file mode 100644
index 0000000..69eb4b8
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt
new file mode 100644
index 0000000..72fc7ea
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt
new file mode 100644
index 0000000..72fc7ea
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt
new file mode 100644
index 0000000..72fc7ea
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42 + 10
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt
new file mode 100644
index 0000000..0bb6121
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt
new file mode 100644
index 0000000..0bb6121
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt
new file mode 100644
index 0000000..0bb6121
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] + 42
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt
new file mode 100644
index 0000000..0294ea7
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 84
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt
new file mode 100644
index 0000000..0294ea7
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 84
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt
new file mode 100644
index 0000000..0294ea7
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt
@@ -0,0 +1,2 @@
+SELECT [e].[Value] * 2 + 84
+FROM [Entity] AS [e]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt
new file mode 100644
index 0000000..a6b0b53
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt
@@ -0,0 +1,3 @@
+[
+ (11,13): error EFP0004: Compound assignment operator '+=' has side effects and cannot be used in projectable methods
+]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt
new file mode 100644
index 0000000..b5f9f5b
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.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 > 10 ? 1 : default;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt
new file mode 100644
index 0000000..c22d885
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.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 > 10 ? 1 : 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt
new file mode 100644
index 0000000..d47a3ba
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt
@@ -0,0 +1,3 @@
+[
+ (12,13): error EFP0004: Increment/decrement operator '++' has side effects and cannot be used in projectable methods
+]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt
new file mode 100644
index 0000000..e940c26
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.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 * 2 > 10 ? 1 : 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt
new file mode 100644
index 0000000..0a7e7da
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.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 * 2 == 2 ? "Two" : @this.Bar * 2 == 4 ? "Four" : "Other";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt
new file mode 100644
index 0000000..587f792
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt
@@ -0,0 +1,3 @@
+[
+ (13,17): warning EFP0003: Method 'Foo' contains an unsupported statement: Local declarations in nested blocks are not supported
+]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt
new file mode 100644
index 0000000..26e6a19
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt
@@ -0,0 +1,3 @@
+[
+ (11,13): warning EFP0005: Method call 'WriteLine' may have side effects. Only calls to methods marked with [Projectable] are guaranteed to be safe in projectable methods
+]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt
new file mode 100644
index 0000000..e684d40
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt
@@ -0,0 +1,3 @@
+[
+ (11,13): error EFP0004: Assignment operation has side effects and cannot be used in projectable methods
+]
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt
new file mode 100644
index 0000000..eeb0754
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.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) => 42;
+ }
+ }
+}
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt
new file mode 100644
index 0000000..d1a7eb5
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.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 == 1 ? "One" : @this.Bar == 2 ? "Two" : "Other";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt
new file mode 100644
index 0000000..c90d6b7
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.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 == 1 || @this.Bar == 2 ? "Low" : @this.Bar == 3 || @this.Bar == 4 || @this.Bar == 5 ? "Medium" : "High";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt
new file mode 100644
index 0000000..0a4d15d
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.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 == 1 ? "One" : @this.Bar == 2 ? "Two" : default;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt
new file mode 100644
index 0000000..c22d885
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.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 > 10 ? 1 : 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt
new file mode 100644
index 0000000..ef8f31a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.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.IsActive && @this.Bar > 0 ? @this.Bar * 2 : 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt
new file mode 100644
index 0000000..d863659
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.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 * 2 + 5;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt
new file mode 100644
index 0000000..7c1426a
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.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_Add_P0_int_P1_int
+ {
+ static global::System.Linq.Expressions.Expression> Expression()
+ {
+ return (global::Foo.C @this, int a, int b) => a + b;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt
new file mode 100644
index 0000000..216b8f2
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.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 > 10 ? "High" : @this.Bar > 5 ? "Medium" : "Low";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt
new file mode 100644
index 0000000..19e29c9
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.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 + 10;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt
new file mode 100644
index 0000000..24ae821
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.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 * 2 + 5 + 10;
+ }
+ }
+}
\ 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 e5b07d2..ae09af6 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
@@ -493,7 +493,7 @@ public int Foo
}
[Fact]
- public void BlockBodiedMethod_RaisesDiagnostics()
+ public void BlockBodiedMethod_NoLongerRaisesDiagnostics()
{
var compilation = CreateCompilation(@"
using System;
@@ -511,7 +511,9 @@ public int Foo()
var result = RunGenerator(compilation);
- Assert.Single(result.Diagnostics);
+ // Block-bodied methods are now supported, so no diagnostics should be raised
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
}
[Fact]
@@ -1977,6 +1979,636 @@ public static Dictionary ToDictionary(this Entity entity)
return Verifier.Verify(result.GeneratedTrees[0].ToString());
}
+ [Fact]
+ public Task BlockBodiedMethod_SimpleReturn()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ [Projectable]
+ public int Foo()
+ {
+ return 42;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithPropertyAccess()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ return Bar + 10;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithIfElse()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ if (Bar > 10)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithNestedIfElse()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public string Foo()
+ {
+ if (Bar > 10)
+ {
+ return ""High"";
+ }
+ else if (Bar > 5)
+ {
+ return ""Medium"";
+ }
+ else
+ {
+ return ""Low"";
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithLocalVariable()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ var temp = Bar * 2;
+ return temp + 5;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithTransitiveLocalVariables()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ var a = Bar * 2;
+ var b = a + 5;
+ return b + 10;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_LocalInIfCondition()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ var threshold = Bar * 2;
+ if (threshold > 10)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_LocalInSwitchExpression()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public string Foo()
+ {
+ var value = Bar * 2;
+ switch (value)
+ {
+ case 2:
+ return ""Two"";
+ case 4:
+ return ""Four"";
+ default:
+ return ""Other"";
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ if (Bar > 10)
+ {
+ var temp = Bar * 2;
+ return temp;
+ }
+ return 0;
+ }
+ }
+}
+", expectedToCompile: true);
+
+ var result = RunGenerator(compilation);
+
+ // Should have a diagnostic about locals in nested blocks
+ Assert.NotEmpty(result.Diagnostics);
+ Assert.Contains(result.Diagnostics, d => d.Id == "EFP0003");
+
+ return Verifier.Verify(result.Diagnostics.Select(d => d.ToString()));
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithMultipleParameters()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ [Projectable]
+ public int Add(int a, int b)
+ {
+ return a + b;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_WithIfElseAndCondition()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+ public bool IsActive { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ if (IsActive && Bar > 0)
+ {
+ return Bar * 2;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+
+ [Fact]
+ public Task BlockBodiedMethod_IfWithoutElse_UsesDefault()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ if (Bar > 10)
+ {
+ return 1;
+ }
+ return 0;
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_IfWithoutElse_ImplicitReturn()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int? Foo()
+ {
+ if (Bar > 10)
+ {
+ return 1;
+ }
+ }
+ }
+}
+", expectedToCompile: false);
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_SwitchStatement_Simple()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public string Foo()
+ {
+ switch (Bar)
+ {
+ case 1:
+ return ""One"";
+ case 2:
+ return ""Two"";
+ default:
+ return ""Other"";
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_SwitchStatement_WithMultipleCases()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public string Foo()
+ {
+ switch (Bar)
+ {
+ case 1:
+ case 2:
+ return ""Low"";
+ case 3:
+ case 4:
+ case 5:
+ return ""Medium"";
+ default:
+ return ""High"";
+ }
+ }
+ }
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_SwitchStatement_WithoutDefault()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public string? Foo()
+ {
+ switch (Bar)
+ {
+ case 1:
+ return ""One"";
+ case 2:
+ return ""Two"";
+ }
+ }
+ }
+}
+", expectedToCompile: false);
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_PropertyAssignment_ReportsError()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ Bar = 10;
+ return Bar;
+ }
+ }
+}
+", expectedToCompile: true);
+
+ var result = RunGenerator(compilation);
+
+ // Should have a diagnostic about side effects
+ Assert.NotEmpty(result.Diagnostics);
+ Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004");
+
+ return Verifier.Verify(result.Diagnostics.Select(d => d.ToString()));
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_CompoundAssignment_ReportsError()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ Bar += 10;
+ return Bar;
+ }
+ }
+}
+", expectedToCompile: true);
+
+ var result = RunGenerator(compilation);
+
+ // Should have a diagnostic about side effects
+ Assert.NotEmpty(result.Diagnostics);
+ Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004");
+
+ return Verifier.Verify(result.Diagnostics.Select(d => d.ToString()));
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_IncrementOperator_ReportsError()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ var x = 5;
+ x++;
+ return x;
+ }
+ }
+}
+", expectedToCompile: true);
+
+ var result = RunGenerator(compilation);
+
+ // Should have a diagnostic about side effects
+ Assert.NotEmpty(result.Diagnostics);
+ Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004");
+
+ return Verifier.Verify(result.Diagnostics.Select(d => d.ToString()));
+ }
+
+ [Fact]
+ public Task BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning()
+ {
+ var compilation = CreateCompilation(@"
+using System;
+using EntityFrameworkCore.Projectables;
+namespace Foo {
+ class C {
+ public int Bar { get; set; }
+
+ [Projectable]
+ public int Foo()
+ {
+ Console.WriteLine(""test"");
+ return Bar;
+ }
+ }
+}
+", expectedToCompile: true);
+
+ var result = RunGenerator(compilation);
+
+ // Should have a diagnostic about potential side effects
+ Assert.NotEmpty(result.Diagnostics);
+ Assert.Contains(result.Diagnostics, d => d.Id == "EFP0005");
+
+ return Verifier.Verify(result.Diagnostics.Select(d => d.ToString()));
+ }
+
[Fact]
public Task MethodOverloads_WithDifferentParameterTypes()
{