首页 > 解决方案 > 在实体配置中使用 EF Core HasQueryFilter 将可为空的数据库列映射到不可为空的属性?

问题描述

设置:

在 MS SQL Server 数据库中(注意:由外部提供程序管理,我们无法更改架构)我们有一个可以为空的表列。同时,在我们的实体模型中,我们特意指定映射到该列的属性不可为空(因为我们希望完全忽略null该属性的所有情况,也不想在我们的代码中进行任何属性转换)。

自然,在运行时,当 EF Core 尝试将可空数据映射到不可空属性时,这将在查询执行时导致异常。

因此我们认为,我们可以使用 EF Core 的HasQueryFilter,它“指定一个 LINQ 谓词表达式,该表达式将自动应用于针对此实体类型的任何查询”。这个想法是,通过使用HasQueryFilter,我们可以忽略映射到该列的属性为空的所有情况。这样,在执行查询时,可以保证在 EF Core 进行映射之前,从结果集中删除该列的所有具有空值的行。

这是示例实体配置:

namespace Foo.Bar.Baz
{
  public class MyEntity : IEntityTypeConfiguration<MyEntity>
  {
    public int Id { get; set; }
    public int Foo { get; set; }

    public void Configure(EntityTypeBuilder<MyEntity> builder)
    {
      builder.ToTable("myTable");
      builder.HasKey(e => e.Id);
      builder.HasQueryFilter(e =>
        e.Foo != null // <-- ignoring any datasets with Foo being null
      );
    }
  }
}

问题:

当通过例如...对该实体执行查询时

DbContext.Set<MyEntity>().ToList();

....HasQueryFilter已执行,但该e.Foo != null部分似乎已从WHERESQL 查询的部分中删除,因为 EF Core 的优化机制认为它是一个“始终为真”的表达式。

问题:

任何想法如何强制 EF Core 执行过滤器部分.HasQueryFilter或如何配置实体以实现我们上面描述的内容?

PS 请注意,我们知道我们可以添加另一个服务层来执行另一个映射,或者我们可以引入另一个属性来正确映射列。但我们希望避免这种情况,并通过实体类型构建器配置透明地处理这种情况。

标签: c#sql-server.net-corelinq-to-sqlentity-framework-core

解决方案


看起来 EF 将优化查询过滤器以删除对所需属性的任何非空检查。如果您从属性中删除[Required]属性并仅使用查询过滤器,它应该可以工作。或者保留该[Required]属性,以便您可以在运行时使用它,但在模型配置中覆盖它。

builder.Property(e => e.Foo).IsRequired(false);

推荐阅读