函数,该函数可以采用不同的表并对公共列进行操作

本文关键字:函数 操作 | 更新日期: 2023-09-27 18:25:25

我有许多不同的表,每个表都有一些公共列和一些对每个表唯一的列。我正在使用实体框架对这些表进行操作,并使用LINQ查询进行筛选、排序等。下面的代码是我遇到的一个高度简化的情况示例。

        var filter = "A";
        using (var dc = new MyDataEntities())
        {
            var rpt1 = dc.Table1.Where(x => x.Name.StartsWith(filter));
            var rpt2 = dc.Table2.Where(x => x.Name.StartsWith(filter));
            var rpt3 = dc.Table3.Where(x => x.Name.StartsWith(filter));
        }

例如,如果我决定要将过滤器从StartsWith更改为Contains,我必须在3个地方进行更改。如果我决定要添加排序,我必须在3个位置添加它,等等

是否有某种方法可以编写一个可以接受任何表并对该表中的公共列进行操作的函数?所以我的最终结果是:

        using (var dc = new MyDataEntities())
        {
            var rpt1 = Filter(dc.Table1);
            var rpt2 = Filter(dc.Table2);
            var rpt3 = Filter(dc.Table3);
        }

这样,我就可以将在任何表的Name列上进行筛选的逻辑放入一个filter()函数中。想法?

函数,该函数可以采用不同的表并对公共列进行操作

让我定义所有涉及的类:

public class Table1
{
    public string Name { get; set; }
}
public class Table2
{
    public string Name { get; set; }
}
public class Table3
{
    public string Name { get; set; }
}

正如你所知,POCO将更加复杂,但对于这个例子来说,它应该很好:

public class Example
{
    public void Test()
    {
        var t1 = new List<Table1>();
        var t2 = new List<Table2>();
        var t3 = new List<Table3>();
        var filter = "hello";
        Func<string, bool> filterFunc = (x) => x.StartsWith(filter);
        var rpt1 = t1.Where(x => filterFunc(x.Name));
        var rpt2 = t2.Where(x => filterFunc(x.Name));
        var rpt3 = t3.Where(x => filterFunc(x.Name));
    }
}

正如你所看到的,我已经将过滤器抽象为一个函数委托

现在,一个可能的更好的解决方案,取决于这是否真的有意义,是将所有共享列放入一个基类中,所有这些都源自:

public class TableCommon
{
    public string Name { get; set; }
}
public class Table1 : TableCommon
{}
public class Table2 : TableCommon
{}
public class Table3 : TableCommon
{}

public class Example
{
    public void Test2()
    {
        var t1 = new List<Table1>();
        var t2 = new List<Table2>();
        var t3 = new List<Table3>();
        var rpt1 = FilterData(t1);
        var rpt2 = FilterData(t2);
        var rpt3 = FilterData(t3);
    }
    public IEnumerable<T> FilterData<T>(IEnumerable<T> data) where T : TableCommon
    {
        var filter = "hello";
        Func<T, bool> pred = (x) => x.Name.StartsWith(filter);
        return data.Where(pred);
    }
}

这样做的好处是,现在你可以隐藏你的过滤器逻辑,甚至可以通过将pred变量作为参数来传递不同的过滤器,并允许这个函数更加通用。

现在,如果您对使用基类和FilterData上的Type约束的这种方式感到不舒服,那么您将不得不使用反射,因为其他原因,我不得不这样做,而且它很快就会变得非常混乱和不可读。或者类似于动态linq的东西,它可能再次变得非常混乱。