【问题标题】:What is the right return value for a LINQ join method?LINQ 连接方法的正确返回值是多少?
【发布时间】:2012-08-22 09:04:57
【问题描述】:

我正在开发一个 3 层应用程序。我也在使用 LINQ to SQL 进行数据访问。

DataLayer 有一个返回客户表的函数:

public Table<Customer> getCustomers()
{
    DataContext context = new DataContext();
    Table<Customer> customerTable = context.GetTable<Customer>();

    return customerTable;
}

它被提供给业务层,结果作为IEnumerable&lt;Customer&gt;传递给表示层:

public IEnumerable<Customer> getCustomers()
{
    CustomerDAL customerDAL = new CustomerDAL();

    return from c in customerDAL.getCustomers() select c;            
}

在表示层中,我只是将 IEnumerable 用于 DatagridView 的数据源。

如果我有另一个表格,如“信息”和相应的 customerDAL.getInfo() 表格,该怎么办?现在我想在业务层的方法中进行连接查询。我想象它是这样的:

public IEnumerable<Customer> getCustomerInfo()
{
    CustomerDAL customerDAL = new CustomerDAL ();

    return from c in customerDAL.getCustomers()
                  join i in customerDAL.getInfo() on c.id equals i.InfoID
                  select new { c.id, c.Name, i.DateTime, i.Project };
}

问题是 IEnumerable 需要对象的类型。我的返回值不再是客户表,而是客户表和信息表的组合。我做对了吗?此处返回值的正确选择是什么?

根据您的建议,我创建了一个自定义类,CustomerInfo.cs

public class CustomerInfo
    {        
        string name { get; set; }
        long id { get; set; }
        string dateTime { get; set; }
        string project { get; set; }


        public CustomerInfo(long _id, string _name, string _date, string _project) 
        {
            name = _name;
            id = _id;
            dateTime = _date;
            project = _project;
        }
    }

然后我调用与 Reed 描述的完全相同的方法。但是在表示层中,当我设置 DataSource 时,我得到了异常:

The query contains references to items defined on a different data context.

实际上,并非所有实体类都在同一个 .dbml 文件中。有什么问题?

【问题讨论】:

    标签: c# .net linq-to-sql 3-tier


    【解决方案1】:

    关于第二个错误:

    然后我调用与 Reed 描述的完全相同的方法。但是在表示层中,当我设置数据源时,我得到了异常: 该查询包含对在不同数据上下文中定义的项目的引用。

    您的 DAL 很可能正在为您返回的每个表实例化一个单独的上下文实例(在 ActiveRecord 模式实现中是典型的)。为了使连接起作用,两个表都需要由同一个上下文对象检索。您可能需要修改 DAL,以便在 DAL 的构造函数中注入上下文,以便集中上下文的生命周期。

    【讨论】:

      【解决方案2】:

      这里返回值的正确选择是什么?

      如果你想返回一个强类型的类,你需要一个自定义的类来表示这个类型,比如一个CustomerInfo类。您需要定义此类,并包含适当的属性和构造函数。然后你可以这样做:

      public IEnumerable<CustomerInfo> GetCustomerInfo()
      {
              CustomerDAL customerDAL = new CustomerDAL();
      
              return from c in customerDAL.getCustomers()
                          join i in customerDAL.getInfo() on c.id equals i.InfoID
                          select new CustomerInfo(c.id, c.Name, i.DateTime, i.Project);
      }
      

      这将允许您以强类型的方式返回所需的确切信息。我认为在这种情况下创建自定义类尤其重要,因为您已将其定义为公共 API 的一部分。

      【讨论】:

      • 这是否意味着我正在对填充有 IEnumerables 的自定义类运行 LINQ 查询,并且我可以将返回值用作数据源?
      • @Prot 不——当然,您可以使用 LINQ to Objects 来过滤结果,但它不再是对数据库起作用的 DataSource。
      【解决方案3】:

      到目前为止,一切看起来都不错。如果您只想在单个方法的范围内使用查询,那么使用匿名类(这是您当前正在做的)就可以了。既然你不是,你需要为你的投影创建一个具体的类,以便你可以返回它。

      查询将变为:

      select new SomeClassYouAreAboutToCreate { c.id, c.Name, i.DateTime, i.Project };
      

      该类可能只有一堆属性,idName 等。您只需在 Select 中设置这些属性。

      【讨论】:

      • 这是否意味着我正在对填充有 IEnumerables 的自定义类运行 LINQ 查询,并且我可以将返回值用作数据源?
      【解决方案4】:

      当你创建一个这样的匿名对象时,它的类型是dynamic。因此,要返回这样的匿名对象列表,您将使用以下签名:

      public IEnumerable<dynamic> getCustomerInfo() {
          CustomerDAL customerDAL = new CustomerDAL ();
      
          return from c in customerDAL.getCustomers()
              join i in customerDAL.getInfo() on c.id equals i.InfoID
              select new { c.id, c.Name, i.DateTime, i.Project };
      }
      

      但请记住,dynamic 类型有其缺点。特别是,您失去了强类型,这可能会引入难以发现的错误。您应该考虑使用Servy's answer 以获得更强大的解决方案。

      【讨论】:

      • dype 不是动态的。它是匿名的强类型。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      相关资源
      最近更新 更多