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

本文关键字:实体 方法 可重用 to 包装 何创建 创建 LINQ Entities | 更新日期: 2023-09-27 18:30:21

>SETUP
我有一个"订单"类和一个"订单详细信息"类。
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 无法识别方法 'System.Linq.IQueryable'1[Models.OrderDetail] GetData(Models.OrderEntities)' 方法,并且此方法无法转换为存储表达式。

请求
我希望 Order.GetData 方法使用 LINQ 调用 OrderDetail.GetData 方法。
我需要将 GetData 方法"联接"在一起,或者在 Order.GetData 类中"子选择"OrderDetail.GetData。
这两个类都在它们的 GetData 方法中查询 EntityFramework。
投影是一项要求。
我的目标是在我的DTO类中创建"可重用"方法,如"GetData",这些方法将包含特定的SQL/实体逻辑。
例如,我在 DTO 类中使用了许多自定义 SQL 函数,如"db.yyyyMMddToDate",将实体转换为对对象/.NET 更友好的东西,我不想每次需要从实体"联接/子选择"数据时"重新键入"所有这些逻辑。

在 LINQ to Objects 中,这与联接来自不同类的两个不同列表相同。
但似乎 LINQ to Entity 不知道如何联接来自其他类的方法,即使该方法被标记为可查询。
我知道 LINQ to Entity 将"GetData"方法视为 SQL 函数,但我需要一种方法来告诉 LINQ to Entity,这些只是将更多实体连接在一起以获得结果。

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

您收到此错误是因为,在处理 LINQ to Entities 时,您不会像在 LINQ to Object 中那样将 lambda 传递给 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);

此查询将向远程服务器询问订单 ID 为 1 的所有订单及其所有匹配的订单详细信息。然后,EF 将自动为你创建所有相关的客户端实体。

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