-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArgumentNullException when comparing niladic functions #24166
Comments
Can you share a real LINQ query example where this is blocking? |
This is a bit closer to a real-life query, runnable on any Oracle instance: <PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.1" /> program [Table("DUAL")]
class Dual
{
[Key]
[Column("DUMMY")]
public string Dummy { get; set; }
}
class AppDb : DbContext
{
public AppDb(DbContextOptions<AppDb> options) : base(options)
{
}
public DbSet<Dual> Dual { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDbFunction(() => Fn.User()).HasTranslation(args => new SqlFunctionExpression("USER", false, typeof(string), null));
}
}
static class Fn
{
public static string User() => throw new NotImplementedException("No client eval");
}
class Program
{
static void Main()
{
var services = new ServiceCollection();
services.AddDbContext<AppDb>(opts =>
{
opts.UseOracle("...");
});
var svc = services.BuildServiceProvider();
var db = svc.GetRequiredService<AppDb>();
var q = from d in db.Dual
select new
{
Creator = Fn.User(),
Updater = Fn.User(),
};
var i = q.ToList();
}
} Expected command text: class MyTable
{
[Key] public int Type { get; set; }
public string Creator { get; set; }
public string Updater { get; set; }
}
public DbSet<MyTable> MyTable { get; set; }
var q = from d in db.MyTable
select new
{
Creator = d.Type == 1 ? Fn.User() : d.Creator,
Updater = d.Type == 1 ? Fn.User() : d.Updater,
}; but this does not: var q = from d in db.MyTable
select new
{
Creator = d.Type != 1 ? d.Creator : Fn.User(),
Updater = d.Type != 1 ? d.Updater : Fn.User(),
}; A simple workaround that comes to my mind: .HasTranslation(args => new SqlFragmentExpression("USER")); but now the command text is Another possible workaround I found is a custom expression type like so: .HasTranslation(args => new NiladicFunctionExpression("USER", false, typeof(string), null));
class NiladicFunctionExpression : SqlFunctionExpression
{
public NiladicFunctionExpression(string functionName, bool nullable, Type type, RelationalTypeMapping typeMapping) : base(functionName, nullable, type, typeMapping)
{
}
public override bool IsNiladic => true;
public override IReadOnlyList<SqlExpression> Arguments => Array.Empty<SqlExpression>();
} then I get Side note: the function here is deterministic but e.g. |
@bachratyg See the planning process for information on how we decide which issues to patch. At the moment we're having trouble understanding the real impact of this on production code. Can you try to explain what is blocked in your production scenarios so that we can better articulate the impact when taking this to the directors for patch approval? |
I managed to map all affected functions to behavior-equivalent non-niladic db calls (e.g. Closing as this is no longer a critical/blocking issue since there's a viable workaround and the bug seems already fixed in v6. Note for posterity: as it turns out this is a regression in v5 from v3.1. The following translation works in v3.1: ...HasTranslation(_ => new SqlFunctionExpression(null, null, "USER", true, null, true, typeof(string), null)); |
When using niladic functions query execution may throw an ArgumentNullException.
I think the bug is here: https://github.com/dotnet/efcore/blob/v5.0.3/src/EFCore.Relational/Query/SqlExpressions/SqlFunctionExpression.cs#L389 Null check missing for the Arguments property.
Seems like this was already fixed in #23296 for v6 but still an issue for v5.
Repro code
Project.csproj
Program.cs - simplest
Program.cs - using expression factory
Exception thrown
The actual production code where I'm hitting this is much more involved and for legal reasons I cannot disclose it, however the root cause seems to be the same: query execution triggers SqlFunctionExpression.Equals. Exception stack trace:
Provider and version information
EF Core version: 5.0.3
Database provider: Microsoft.EntityFrameworkCore.SqlServer - does not seem to matter, code path does not touch provider specifics
Target framework: .NETCore 3.1
Operating system: Windows 10 20H2 (19042.804)
IDE: Visual Studio 2019 16.8.5
The text was updated successfully, but these errors were encountered: