如何使用实体框架管理的类的属性创建动态过滤器?

时间:2019-07-11 00:04:37

标签: c# sql-server entity-framework

我正在使用Entity Framework 6开发应用程序,但无法使用Entity Framework管理的实体类的属性解决动态过滤器的问题。

问题实际上是该类的不可为空的属性(可以将其与null进行比较)。

背景

我正在使用常规框架,使用C#将应用程序分为3个项目(模型,视图,控制器)。

使用SQL Server 2017作为数据库和实体框架(不是Core)。

我尝试过的事情

我做了几个Google查询,但没有一个能解决我的问题。

最接近解决方案的答案是Entity Framework Core - dynamic filtering用户Marcio Martins,但是我对如何处理非空属性一无所知。

会有人知道如何解决此问题吗?

代码

我需要找到一种将以下查询转换为lambda或linq表达式的方法:

-- Sql Server query
declare @ProductID int
declare @Name nvarchar(600)
declare @BarCode nvarchar(26)
declare @Active bit
declare @Price decimal

select
    p.ProductID
    , p.Name
    , p.BarCode
    , p.Active
    , p.Price
from
    Product p
where
    (@ProductID is null or p.ProductID = @ProductID)
    and (@Name is null or p.Name = @Name)
    and (@BarCode is null or p.BarCode = @BarCode)
    and (@Active is null or p.Active = @Active)
    and (@Price is null or p.Price = @Price)

实体类

public class Package
{
    [Key]
    public Int32 PackageID { get; set; }
    [Required]
    [MaxLength(20)]
    public String Name { get; set; }
    public Boolean Active { get; set; }
}

View中的代码段。

List<Package> packages = new PackageController().Retreave();
// Dynamic query here!

编辑

我尝试了这个,但是没有用:

List<Package> packages = new PackageController().Retrieve()
                                                .Where(p =>  String.IsNullOrEmpty(p.Name) || p.Name.Contains(package.Name))
                                                .ToList();

预期:

主要思想是使查询变得灵活,以便最终用户可以通过实体类的任何属性来过滤数据。

Ex:用户选择包名的名称或一部分,并且不指示记录是否处于活动状态,考虑到上述查询,仅会通知Name属性,Active属性将接收空值,并且查询将返回“包名称”是用户选择的“包名称”之一的所有值,无论它是处于活动状态还是已停用。

实际结果

由于我无法调整动态过滤器,因此,如果用户通知程序包的“名称”属性或“名称”的一部分而没有说出它是否处于活动状态,则.NET会自动初始化的值。将Package的“ Active”属性设置为false,这最终将返回所有禁用的Package,其名称或用户选择的名称的一部分。

2 个答案:

答案 0 :(得分:0)

使属性 Active 可为空(因此与数据库中的字段类型匹配),它将解决您的问题。

实体类:

public class Package
{
    ...
    public Boolean? Active { get; set; }
}

答案 1 :(得分:0)

非常感谢您的看到和回应。 经过一些测试以及Przemek Marcinkiewicz回答我的想法,我得以解决问题。 来吧,这个答案可以在将来帮助很多人。 我需要使Package类的属性为可空的,但是在不更改库模型的情况下,我是通过这样配置类来做到这一点的:

public class Package
{
    [Key]
    [Required]
    public Int32? PackageID { get; set; }
    [Required]
    [MaxLength(20)]
    public String Name { get; set; }
    [Required]
    public Boolean Active? { get; set; }
}

到目前为止,好的,我需要以某种方式使用查询机制,并且能够通过调用称为过程的Entity框架并使用可为空的参数来做到这一点,最终结果是这样的:

public List<Package> Retreave(Package entity)
{
    using (MyDatabaseContext db = new MyDatabaseContext())
    {
        return db.Database
            .SqlQuery<Package>
            (
                "PROC_PACKAGE_SELECT @PackageID, @Name, @Active"
                , new SqlParameter("@PackageID", (object)entity.PackageID ?? DBNull.Value)
                , new SqlParameter("@Name", (object)entity.Name ?? DBNull.Value)
                , new SqlParameter("@Active", (object)entity.Active ?? DBNull.Value)
            )
                .ToList<Package>();
    }
}

我进行了几次测试,在这种情况下,查询可以100%灵活地满足我的需求。

我真的希望这项工作可以为社区中的某人提供帮助。