从原始SQL创建实体图

时间:2016-12-18 22:34:25

标签: sql sql-server entity-framework linq

因为当n变大时,EF Contains查询非常慢(参见Why is .Contains slow? Most efficient way to get multiple entities by primary key?),我们正在考虑使用原始SQL查询,即使用context.Database.SqlQuery(sql)。

我喜欢EF(我认为每个人都喜欢),就是你得到了一个完整的实体图。例如,如果您想要所有客户,每个客户都有他们的订单列表,您可能会写这样的内容:

    public IEnumerable<Customer> GetCustomersById(List<int> ids)
    {
        using (var db = new ShoppingCartEntities())
        {
            return db.Customers
                .Include(c => c.Orders)
                .Where(ids.Contains(c => c.CustomerID));
        }
    }

当然这是一个简化的查询。在现实世界中,我带回了更多的列,我可能会使用.Select来创建一个匿名类型来解决一些序列化问题。

这很好,因为你得到了一个类型为Customer的IEnumerable,每个都有一个名为Orders的属性,它是一个类型为Order的IEnumerable。

使用原始SQL,我可能会执行以下操作:

    public IEnumerable<Customer> GetCustomersById(List<int> ids)
    {
        string idsString = string.Join(",", ids);
        using (var context = new ShoppingCartEntities())
        {
            string sql = string.Format(@"
                SELECT C.CustomerID, C.Name, C.Address, O.OrderID, O.OrderDate, O.OrderTotal
                FROM
                    Customer C
                        LEFT JOIN Order O
                            ON O.CustomerID = C.CustomerId
                    WHERE C.CustomerID IN ({0})", idsString);

            var results = context.Database.SqlQuery<Customer>(sql);
            return results;
        }
    }

正如我们都知道的那样(https://entityframework.codeplex.com/workitem/118),实体框架不会像现在这样给出一个对象图,而是一个Customer列表,每个都有一个null Orders属性。太糟糕了。

据我所知,我此时的选择是

  1. 遍历不同的Customer行,手动构建Order的实例,然后将它们添加到Customer的Order属性中,或
  2. 放弃实体框架,并执行与#1类似的操作,但使用自定义业务对象。
  3. 我很好奇是否有人有处理此问题的第一手经验。我四处搜寻,没找到任何合适的账单。

    请注意,我们首先需要包含或IN查询的原因是我们从另一个我们无法控制的服务中获取ID列表。另请注意,上述SQL中的LEFT JOIN是必要的,因为我们需要所有客户,甚至是没有订单的客户。

    谢谢!

0 个答案:

没有答案