LINQ to Entities。如何创建“包装”实体的“可重用”方法?

时间:2014-11-13 18:06:26

标签: c# linq entity-framework

SETUP
我有一个"订单" class和" OrderDetail"类。
Order类有一个名为" OrderDetails"类型IQueryable。
我在每个类中都有一个名为" GetData"并且此方法返回其所在类的IQueryable " GetData"方法是实体周围的包装器,用于将实体转换为更友好的.NET类/属性 例如:OrderDetail实体有一个" PullDate"在数据库中作为Char(10)但我希望OrderDetail类具有一个名为" PullDate"的属性。这是类中DateTime的类型。

代码

public class Order
{
    [Key]
    public int ID { get; set; }
    public IQueryable<OrderDetail> OrderDetails { get; set; }

    public static IQueryable<Order> GetData()
    {
        IQueryable<Order> orders;
        var db = new OrderEntities();

        // NOTE: This code will work
        try
        {
            var data = 
                (from O in db.Orders
                 where O.OrderID == 1
                 select new Order
                 {
                     ID = O.OrderID,
                     OrderDetails = 
                         (from OD in db.OrderDetails
                          where OD.OrderID == O.OrderID
                          select new OrderDetail
                          {
                              ID = OD.OrderDetailID,
                              OrderID = OD.OrderID,
                              PullDate = OD.PullDate == "00000000" ?
                                  (DateTime?)null : db.yyyyMMddToDate(OD.PullDate),
                              Description = OD.Desc
                          })
                 });

            orders = data.AsQueryable();
            var orderList = orders.ToList();
        }
        catch (Exception ex)
        {                
            throw;
        }

        // NOTE: This code will NOT work
        try
        {
            var data = (from O in db.Orders
                        where O.OrderID == 1
                        select new Order
                        {
                            ID = O.OrderID,
                            OrderDetails = (from OD in OrderDetail.GetData(db)
                                            where OD.OrderID == O.OrderID
                                            select OD)
                        });

            orders = data.AsQueryable();
            var orderList = orders.ToList();
        }
        catch (Exception ex)
        {

            throw;
        }

        return orders;
    }
}


public class OrderDetail
{
    [Key]
    public int ID { get; set; }
    public int OrderID { get; set; }
    public DateTime? PullDate { get; set; }
    public string Description { get; set; }

    public static IQueryable<OrderDetail> GetData(OrderEntities db)
    {
        IQueryable<OrderDetail> orderDetails;

            var data = (from OD in db.OrderDetails
                        select new OrderDetail
                        {
                            ID = OD.OrderDetailID,
                            OrderID = OD.OrderID,
                            PullDate = OD.PullDate == "00000000" ?
                                (DateTime?)null : db.yyyyMMddToDate(OD.PullDate),
                            Description = OD.Desc
                        });

            orderDetails = data.AsQueryable();
            var orderList = orderDetails.ToList();

            return orderDetails;
    }
}

错误
    LINQ to Entities无法识别方法&#39; System.Linq.IQueryable`1 [Models.OrderDetail] GetData(Models.OrderEntities)&#39;方法,并且此方法无法转换为商店表达式。

请求
我希望Order.GetData方法使用LINQ调用OrderDetail.GetData方法 我需要加入&#34; GetData方法在一起或&#34; sub select&#34;在Order.GetData类中的OrderDetail.GetData 这两个类都在其GetData方法中查询EntityFramework 预测是一项要求 我的目标是创造&#34;可重复使用&#34;方法如&#34; GetData&#34;在我的DTO类中将包含特定的SQL /实体逻辑 例如,我使用了许多自定义SQL函数,例如&#34; db.yyyyMMddToDate&#34;在我的DTO课程中,将实体转换为更加对象/ .NET友好的东西,我不想重新输入&#34;每次我需要的所有逻辑&#34;加入/子选择&#34;来自实体的数据。

在LINQ to Objects中,这与从不同的类加入两个不同的列表相同 但似乎LINQ to Entity不知道如何从其他类连接方法,即使该方法被标记为可查询。
我知道LINQ to Entity正在处理&#34; GetData&#34;方法好像它们是SQL函数,但我需要一种方法来告诉LINQ to Entity这些只是更多的实体连接在一起以获得结果。

1 个答案:

答案 0 :(得分:1)

你得到这个错误,因为在处理LINQ to Entities时,你没有像在LINQ to Object中那样将lambdas传递给LINQ运算符。你正在传递表达树。您在这些查询中编写的代码将永远不会被执行。它将被实体框架解释为一系列转换为SQL等其他语言的指令。

GetData方法在SQL中没有任何意义。事实上,它并不意味着你自己的程序之外的任何东西。这就是LINQ to Entities无法将您的方法识别为有效构造的原因。

要在类似您的方案中访问订单的详细信息,您需要构建查询,以便EF知道使用Include运算符在主查询中包含OrderDetails实体。执行此操作时,EF希望您的对象具有与此类似的属性:

public virtual ICollection<OrderDetail> OrderDetails { get; set; }

这就是EF将如何知道从包含这些元素的查询中生成对象的位置。

var ctx = new DatabaseContext();
var query = ctx.Orders
   .Where(o => o.OrderId == 1)
   .Include(o => o.OrderDetails);

此查询将向远程服务器请求OrderId为1的所有订单及其所有匹配的OrderDetails。然后,EF将自动为您创建所有相关的客户端实体。

以下是EF关于此主题的官方文档:http://msdn.microsoft.com/en-ca/data/jj574232.aspx