使用通用方法返回 list<T>,其中 T 可以是三种共享相同结构的类型之一。

3

我有一些SQL视图,使用不同的源表,但每个视图返回完全相同的结构。

简单来说:

view1
    select tblA.Name as custName,
           tblA.DOB as DateOfBirth,
           tblA.accountBalance as AccountBalance
    from myFirstTable tblA

view2
    select tblB.AccountName as custName,
           tblB.BirthDate as DateOfBirth,
           tblB.Balance as AccountBalance
    from mySecondTable tblB

view3
    select tblC.CustomerName as custName,
           tblC.DateOfBirth as DateOfBirth,
           tblC.accBal as AccountBalance
    from myThirdTable tblC

所以,即使源表中的字段名称不同,不同的视图返回具有相同名称(和类型)的字段。实际视图是复杂而庞大的,每个视图运行到数百行。

然后,我将这些视图拖入我的 Linq-to-sql 设计器中,并尝试在通用类中使用它们。

    public static List<T> MainSearch<T>(ReportParams RP)
    {
        MyDataContext dc = new MyDataContext();

        if (string.IsNullOrEmpty(RP.appType)) { return null; }

        var searchQuery = new List<T>();

        switch (RP.appType)
        {
            case "type1":
                searchQuery = (from t in dc.view1s select t);
                break;
            case "type2":
                searchQuery = (from t in dc.view2s select t);
                break;
            case "type3":
                searchQuery = (from t in dc.view3s select t);
                break;
        }

        //do other stuff with search query depending on params
        DateTime dtFrom = Convert.ToDateTime(RP.fromDate);
        searchQuery = searchQuery.Where(q => convert.ToDateTime(q.DateOfBirth) >= dtFrom);

        //and so on...

这里的想法是使用通用前端,根据用户选择传递参数,然后这些参数用于缩小对特定源数据的搜索结果(永远不会返回组合,始终只有三种视图之一)。
上述代码无法运行。在我的switch语句中,智能感知会抱怨无法隐式转换从特定类型(例如view1)到T的泛型列表。这使我无法在lambda表达式中继续使用强类型。
是否有任何方法可以实现我正在尝试做的事情,或者我完全错了?
3个回答

2

如果你有一个类,其属性集与视图返回的相同,则可以尝试如下:

case "type1":
searchquery = (from t in dc.view1s select new commonClass() { CustName = t.CustName, DateOfBirth = t.DateOfBirth, AccountBalance = t.AccountBalance });
                break;

其他情况同理...


这很简单 :) - andyb
这可能是唯一的前进方式。这意味着,由于每个视图大约有60个字段,我将最终得到三个不同视图到公共类的60个手动映射。我可以复制/粘贴它并只更改视图名称,但那似乎非常不优雅! - TheMook
我以前没有使用过AutoMapper,但它可能是值得一试的东西,可以避免手动映射。开始使用:AutoMapper 这里有一个关于如何使用AutoMapper映射对象列表的SO问题:Map lists of objects - Uday

2

我还没有完全测试过,但我认为你可以通过创建一个带有属性custName、DOB和AccountBalance的接口来实现。然后,在单独的部分类文件中让每个生成的LINQ-to-SQL类(tblA、tblB、tblC)实现这个接口。只要属性名和类型匹配,这应该是可以的。

interface IAccountTable
{
    string custName { get; set; }
    DateTime DOB { get; set; }
    Decimal AccountBalance { get; set; }
}

并且

partial class tblA : IAccountTable
{
}

将您的searchQuery转换为该接口的列表。
var searchQuery = new List<IAccountTable>();

将实际查询结果转换为接口的格式。
searchQuery = tblA.Where(t => t.custName == "Uday").Select(t => (IAccountTable)t).ToList();

Linq-to-SQL不支持这种继承,对吗?每次我触碰设计器时,都会覆盖我所做的任何自定义更改。由于视图返回大约60个字段,将它们全部分开维护可能会让人感到沮丧,但我开始认为无论采取哪种方式,我都必须做出类似的事情。 - TheMook
好的...但是"...designer.cs"文件中的部分类必须映射到数据库上的视图源,以便查询知道从哪里获取它。所以我有:[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.view1")],在它下面是public partial class view1,然后是属性列表(在designer.cs文件中)。您是说我需要将其更改为仅继承接口并保留映射吗? - TheMook
不要在同一文件中创建多个视图。为每个视图创建一个单独的部分类文件,其类名相同。将这些文件保存在单独的文件夹中,并将它们命名为tblA.Partial.cs(或其他名称)。在这些新的部分类文件中,指定该类实现接口。编译器会将这些单独的部分类文件组合成一个单一的类。 - andyb
我尝试从服务器资源管理器中拖入视图的另一个实例。然后,我删除了所有属性并修改了设计师以继承接口。一切似乎都很好,但是只要我打开并保存dbml文件,它就会清除继承关系。我不知道如何在不使用dbml的情况下连接到sql视图源?我不能只创建一个单独的类,因为数据上下文不知道去哪里获取数据,对吗? - TheMook
让我们在聊天中继续这个讨论。链接 - andyb
显示剩余3条评论

-1
在Entity Framework中,正确的方法是创建一个单独的TBase类,T1、T2、T3都从这个类派生。它将包含您所需的所有公共属性,因此不需要使用switch语句:您只需要有TBase someObj;然后可以直接使用someObj.ACommonProperty。

我认为LINQ-to-SQL不支持继承。 - andyb
但是当我不使用Entity Framework时,这并没有太大的帮助!我说过我正在使用Linq to SQL。 - TheMook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接