dotnet / dotnet/efcore

Incompatibility with Dbcontext, DbFunction and Interface

Open
#33,025 3 comments 0 reactions 0 assignees View on GitHub
area-model-building area-query customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

## DbFunction don't get the mapping function when an interface is used

There's a strange behavior when an interface is used instead of the direct object of dbcontext when a DbFunciton is called. In the code bellow, I create a function in sql (Test) and added it to my context using DbFunctionAttribute.

If MyDbContext is used to call the Test function works ok. The problem is when the IMyDbContext interface is required to the dependency injection, the Test function throws the NotSupportedException like the mapping doesn't exist.

I tried to cast the interface reference to the base class and works ok, but I believe it's not the desired behavior using interfaces. Also, I tried to add virtual to Test function in MyDbContext, but didn't works with the interface.

### Code

```SQL
CREATE FUNCTION dbo.Test(@i int) RETURNS int AS
begin
return @i;
end
```
```C#
public interface IMyDbContext {
int Test(int i);
}
public class MyDbContext(DbContextOptions dbContextOptions) : DbContext(dbContextOptions), IMyDbContext {
...
[DbFunction("Test", "dbo", IsBuiltIn = false)]
public int Test(int i) => throw new NotSupportedException();
}
// Added both to my dependency injection
var builder = WebApplication.CreateBuilder(args);
builder
.AddDbContext(ServiceLifetime.Transient)
.AddDbContext(ServiceLifetime.Transient);
```

```C#
public class MyController(IMyDbContext iContext, MyDbContext context): ControllerBase
{
public IActionResult TestOk() => Ok(
context.Users.Select(it => context.Test(it.Id))); // using concrete class

public IActionResult TestWrong() => Ok(
iContext .Users.Select(it => iContext .Test(it.Id))); // using interface

public virtual IActionResult TestCastOk()
{
var ctx = iContext as MyDbContext; // using interface, casted to concrete class
return Ok(ctx!.Users.Select(it => ctx.Tomorrow(it.Id)));
}
}
```

### Stack traces
```
[12:43:18 DBG] Compiling query expression:
'DbSet()
.Select(it => __P_0.Test(it.Id))'
[12:43:18 DBG] Generated query execution expression:
'queryContext => new SingleQueryingEnumerable(
(RelationalQueryContext)queryContext,
RelationalCommandCache.QueryExpression(
Client Projections:
0 -> 0
SELECT u.Id
FROM Users.Users AS u),
null,
Func,
MyDbContext,
False,
True,
True
)'
[12:43:18 DBG] Creating DbConnection.
[12:43:18 DBG] Created DbConnection. (2ms).
[12:43:18 DBG] Opening connection to database '' on server ''.
[12:43:18 DBG] Opened connection to database '' on server ''.
[12:43:18 DBG] Creating DbCommand for 'ExecuteReader'.
[12:43:18 DBG] Created DbCommand for 'ExecuteReader' (1ms).
[12:43:18 DBG] Initialized DbCommand for 'ExecuteReader' (3ms).
[12:43:18 DBG] Executing DbCommand [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT [u].[Id]
FROM [Users].[Users] AS [u]
[12:43:18 INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT [u].[Id]
FROM [Users].[Users] AS [u]
[12:43:18 ERR]
```
```
An exception occurred while iterating over the results of a query for context type 'MyDbContext'.
System.NotSupportedException.
at MyDbContext.Test(Int32 i) in MyDbContext.Accounting
at lambda_method39(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
```
```
[12:43:18 DBG] Closing data reader to '' on server ''.
[12:43:18 DBG] A data reader for '' on server '' is being disposed after spending 113ms reading results.
```

### Include provider and version information

EF Core version: Microsoft.EntityFrameworkCore, 8.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer, 8.0.0
Target framework: net8.0
Operating system: Windows 10
IDE: Microsoft Visual Studio Professional 2022 (64-bit) 17.8.3

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.