help
Root Question Message
EF Core 6
, recently I want to use the Global Query Filters
.OnModelCreating
inside my DbContext
I applied the two Gobal Query Filters
shown bellow:query filter
who applied, but the IAuditable
one not applied, please how do I fix this issue ? foreach ( var entityType in modelBuilder.Model.GetEntityTypes() )
{
if ( typeof( IArchivable ).IsAssignableFrom( entityType.ClrType ) )
{
var parameter = Expression.Parameter( entityType.ClrType , "p" );
var isArchivedProperty = MemberExpression.Property(parameter, "IsArchived");
// check isArchived == null
var isArchivedNullCheck = Expression.Equal( isArchivedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isArchivedNullFunc = Expression.Lambda( isArchivedNullCheck , parameter );
// check isArchived == false
var isArchivedFalseCheck = Expression.Equal( isArchivedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isArchivedFalseFunc = Expression.Lambda( isArchivedFalseCheck , parameter );
// Combine the two expressions using OR
var isArchivedCExpression = Expression.OrElse( isArchivedNullCheck , isArchivedFalseCheck );
// Create the lambda expression
var isArchivedFunc = Expression.Lambda( isArchivedCExpression , parameter );
modelBuilder.Entity( entityType.ClrType ).HasQueryFilter( isArchivedFunc );
}
else if ( typeof( IAuditable ).IsAssignableFrom( entityType.ClrType ) )
{
var parameter = Expression.Parameter( entityType.ClrType , "p" );
var isDeletedProperty = MemberExpression.Property(parameter, "IsDeleted");
// check isDeleted == null
var isDeletedNullCheck = Expression.Equal( isDeletedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isDeletedNullFunc = Expression.Lambda( isDeletedNullCheck , parameter );
// check isDeleted == false
var isDeletedFalseCheck = Expression.Equal( isDeletedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isDeletedFalseFunc = Expression.Lambda( isDeletedFalseCheck , parameter );
// Combine the two expressions using OR
var isDeletedCExpression = Expression.OrElse( isDeletedNullCheck , isDeletedFalseCheck ); // IsDeleted == null || IsDeleted == false
// Create the lambda expression
var isDeletedFunc = Expression.Lambda( isDeletedCExpression , parameter ); // p => p.IsDeleted == null || p.IsDeleted == false
modelBuilder.Entity( entityType.ClrType ).HasQueryFilter( isDeletedFunc );
}
}
HasQueryFilter
and try to add another one with HasQueryFilter
, it'll actually replace the old filter.Expression.AndAlso
Note(https://learn.microsoft.com/en-us/ef/core/querying/filters)
It is currently not possible to define multiple query filters on the same entity - only the last one will be applied. However, you can define a single filter with multiple conditions using the logical AND operator (&& in C#).
Entities types
will be differents because one filter should be applied on IAuditable
entities and another filter should be applied on IArchivable
entties. query filter
for every entity
manuallyvar parameter = Expression.Parameter( entityType.ClrType , "p" );
IAuditable
and IArchivable
. So instead of doing an "else-if", you change it to an if-statement that combines the expression.foreach ( var entityType in modelBuilder.Model.GetEntityTypes() )
{
var parameter = Expression.Parameter( entityType.ClrType , "p" );
Expression condition? = null;
if ( typeof( IArchivable ).IsAssignableFrom( entityType.ClrType ) )
{
var isArchivedProperty = MemberExpression.Property(parameter, "IsArchived");
// check isArchived == null
var isArchivedNullCheck = Expression.Equal( isArchivedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isArchivedNullFunc = Expression.Lambda( isArchivedNullCheck , parameter );
// check isArchived == false
var isArchivedFalseCheck = Expression.Equal( isArchivedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isArchivedFalseFunc = Expression.Lambda( isArchivedFalseCheck , parameter );
// Combine the two expressions using OR
condition = Expression.OrElse( isArchivedNullCheck , isArchivedFalseCheck );
}
if ( typeof( IAuditable ).IsAssignableFrom( entityType.ClrType ) )
{
var isDeletedProperty = MemberExpression.Property(parameter, "IsDeleted");
// check isDeleted == null
var isDeletedNullCheck = Expression.Equal( isDeletedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isDeletedNullFunc = Expression.Lambda( isDeletedNullCheck , parameter );
// check isDeleted == false
var isDeletedFalseCheck = Expression.Equal( isDeletedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isDeletedFalseFunc = Expression.Lambda( isDeletedFalseCheck , parameter );
// Combine the two expressions using OR
var isDeletedCExpression = Expression.OrElse( isDeletedNullCheck , isDeletedFalseCheck ); // IsDeleted == null || IsDeleted == false
condition = condition == null ? isDeletedCExpression : Expression.AndAlso( condition , isDeletedCExpression );
}
if ( condition != null )
{
var filter = Expression.Lambda( condition , parameter );
modelBuilder.Entity( entityType.ClrType ).HasQueryFilter( filter );
}
}
foreach ( var entityType in modelBuilder.Model.GetEntityTypes() )
{
var parameter = Expression.Parameter( entityType.ClrType , "p" );
Expression ? conditions = null;
if ( typeof( IArchivable ).IsAssignableFrom( entityType.ClrType ) )
{
var isArchivedProperty = MemberExpression.Property( parameter , "IsArchived" );
// check isArchived == null
var isArchivedNullCheck = Expression.Equal( isArchivedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isArchivedNullFunc = Expression.Lambda( isArchivedNullCheck , parameter );
// check isArchived == false
var isArchivedFalseCheck = Expression.Equal( isArchivedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isArchivedFalseFunc = Expression.Lambda( isArchivedFalseCheck , parameter );
// Combine the two expressions using OR
conditions = Expression.OrElse( isArchivedNullFunc , isArchivedFalseFunc );
}
if ( typeof( IAuditable ).IsAssignableFrom( entityType.ClrType ) )
{
var isDeletedProperty = MemberExpression.Property(parameter, "IsDeleted");
// check isDeleted == null
var isDeletedNullCheck = Expression.Equal( isDeletedProperty , Expression.Constant( null , typeof( bool ? ) ) );
var isDeletedNullFunc = Expression.Lambda( isDeletedNullCheck , parameter );
// check isDeleted == false
var isDeletedFalseCheck = Expression.Equal( isDeletedProperty , Expression.Constant( false , typeof( bool ? ) ) );
var isDeletedFalseFunc = Expression.Lambda( isDeletedFalseCheck , parameter );
// Combine the two expressions using OR
var isDeletedCExpression = Expression.OrElse( isDeletedNullCheck , isDeletedFalseCheck );
// Add the Expression to the Conditions
conditions = conditions == null ? isDeletedCExpression : Expression.AndAlso( conditions , isDeletedCExpression );
}
if ( conditions != null )
{
var filter = Expression.Lambda( conditions , parameter );
modelBuilder.Entity( entityType.ClrType ).HasQueryFilter( filter );
}
}
ASP.net core 6
app I get this exceptionInvalidOperationException: The binary operator OrElse is not defined for the types 'System.Func2[MBSM.Core.Entities.ContinuousFormation,System.Boolean]' and 'System.Func
2[MBSM.Core.Entities.ContinuousFormation,System.Boolean]'.
ContinuousFormation
is : public class ContinuousFormation : IAuditable, IArchivable
{
// Other properties removed for clarity
public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; }
public bool IsEdited { get; set; }
public string LastEditor { get; set; }
public DateTime LastEditDate { get; set; }
public bool? IsDeleted { get; set; }
public string? DeletedBy { get; set; }
public DateTime? DeletedOn { get; set; }
public bool ? IsArchived { get; set; }
public string ArchivedBy { get; set; }
public DateTime ? ArchivedOn { get; set; }
}
conditions = Expression.OrElse( isArchivedNullFunc , isArchivedFalseFunc );
conditions = Expression.OrElse( isArchivedNullCheck , isArchivedFalseCheck );