win7user10 / Laraue.EfCoreTriggers

Library to write triggers in C# with EF.Core
MIT License
112 stars 20 forks source link

Null coalesce not working in SQL Server #56

Closed JarRami closed 1 year ago

JarRami commented 2 years ago

If I have a table like

public class NullableHolder {
    [Key]
    public int ID { get; set; }
    public int? Value { get; set; }
}

And I try to create an AfterInsert trigger with a Condition like

modelBuilder.Entity<NullableHolder>()
    .AfterInsert(trigger => trigger
        .Action(action => action
            .Condition(nh => (nh.Value ?? -1) != 7)
        )
    );

or a similar Update trigger with a condition comparing values, then after doing an Add-Migration I get an error

System.NotSupportedException: Unknown sign of Coalesce at Laraue.EfCoreTriggers.Common.Services.Impl.SqlGenerator.GetOperand(Expression expression) at Laraue.EfCoreTriggers.SqlServer.SqlServerSqlGenerator.GetOperand(Expression expression) ...

This is with the Sql Server triggers package. Is the null coalescing something that could be supported and turned into something like ISNULL(VALUE, -1) <> 7 (or equivalent in whatever SQL product this is run against)?

Unfortunately, I'm not able to run .NET6 so this behaviour is seen against library version 5.3.6.

win7user10 commented 1 year ago

Fixed in 7.0.1/5.4.6

JarRami commented 1 year ago

I'm now getting the following error when adding a migration with these packages:

image

Add-Migration InitialMigration
Build started...
Build succeeded.
System.ArgumentException: Expression of type 'System.Int32' cannot be used for parameter of type 'System.Nullable`1[System.Int32]' of method 'System.Nullable`1[System.Int32] Coalesce[Nullable`1](System.Nullable`1[System.Int32], System.Nullable`1[System.Int32])' (Parameter 'arg1')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.BinaryExpressionVisitor.Visit(BinaryExpression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.ExpressionVisitorFactory.Visit[TExpression](TExpression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.ExpressionVisitorFactory.Visit(Expression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.BinaryExpressionVisitor.<>c__DisplayClass4_0.<Visit>b__1(Expression part)
   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.BinaryExpressionVisitor.Visit(BinaryExpression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.ExpressionVisitorFactory.Visit[TExpression](TExpression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.ExpressionVisitors.ExpressionVisitorFactory.Visit(Expression expression, ArgumentTypes argumentTypes, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.TriggerVisitors.TriggerConditionVisitor.Visit(TriggerCondition triggerAction, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.TriggerVisitors.TriggerActionVisitorFactory.Visit[T](T triggerAction, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.Common.Services.Impl.TriggerVisitors.TriggerActionVisitorFactory.Visit(ITriggerAction triggerAction, VisitedMembers visitedMembers)
   at Laraue.EfCoreTriggers.SqlServer.SqlServerTriggerVisitor.<>c__DisplayClass7_0.<GenerateCreateTriggerSql>b__1(ITriggerAction actionCondition)
   at System.Linq.Enumerable.SelectListIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Laraue.EfCoreTriggers.SqlServer.SqlServerTriggerVisitor.GenerateCreateTriggerSql(ITrigger trigger)
   at Laraue.EfCoreTriggers.Common.Migrations.MigrationsExtensions.ConvertTriggerAnnotationsToSql(ITriggerVisitor triggerVisitor, IModel model)
   at Laraue.EfCoreTriggers.Common.Migrations.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
win7user10 commented 1 year ago

Hi, fix for that in 7.0.2/5.4.7

JarRami commented 1 year ago

This works, thank you