使用原始 SQL 查询绑定复杂模型实体?

Posted

技术标签:

【中文标题】使用原始 SQL 查询绑定复杂模型实体?【英文标题】:Binding Complex Model Entity With Raw SQL Query? 【发布时间】:2018-03-01 06:46:12 【问题描述】:

我一直在使用实体框架,我可以轻松地与实体本身进行复杂的模型绑定,但是当涉及到原始 sql 绑定时,我找不到任何对关系数据库进行复杂绑定的解决方案。

例如,以下是为产品类建模代码的实体-

var prodResult = db.products.Where(p => p.isActive == true).Select(p => new ComplexProductModel
                
                    id = p.id,
                    dateCreated = p.date_created,
                    datePublished = null,
                    desc = p.product_desc,
                    images = db.products_images.Where(pi => pi.prod_id == p.id).Select(pi => pi.prod_img_thumb).ToList(),
                    summary = p.product_summary,
                    title = p.product_name + " " + p.product_code
                ).ToList();

这实现了针对复杂模型的数据,该模型根据查询要求在主复杂模型中包含字符串或类的列表类型。

现在我尝试使用原始 sql 执行运行相同的生成查询,但图像对象的绑定失败。

var rawComplexData = db.Database.SqlQuery<ComplexProductModel>(dynamicSearchQuery).ToList(); 

对于这种情况有什么解决方案吗,我得到的是 10 行数据(对于这个例子),图像为空,应该是 7 行,重复获取的图像进入List&lt;string&gt; images 用于ComplexProductModel

为了更好地理解代码,这里是复杂的产品模型:

public ComplexProductModel 
        long? id  get; set; 
        string title  get; set; 
        string desc  get; set; 
        string summary  get; set; 
        List<string> images  get; set; 
        DateTime? datePublished  get; set; 
        DateTime? dateCreated  get; set; 
    

根据@tchelidze 的请求,这里是dynamicQuery,这基本上是我从实体框架自身生成的内容中获取的:

SELECT 
    [Project2].[C1] AS [C1], 
    [Project2].[id] AS [id], 
    [Project2].[date_created] AS [date_created], 
    [Project2].[C2] AS [C2], 
    [Project2].[product_desc] AS [product_desc], 
    [Project2].[product_summary] AS [product_summary], 
    [Project2].[C3] AS [C3], 
    [Project2].[C4] AS [C4], 
    [Project2].[prod_img_thumb] AS [prod_img_thumb]
    FROM ( SELECT 
        [Extent1].[id] AS [id], 
        [Extent1].[product_desc] AS [product_desc], 
        [Extent1].[product_summary] AS [product_summary], 
        [Extent1].[date_created] AS [date_created], 
        1 AS [C1], 
        CAST(NULL AS datetime2) AS [C2], 
        [Project1].[prod_img_thumb] AS [prod_img_thumb], 
        CASE WHEN ([Extent1].[product_name] IS NULL) THEN N'' ELSE [Extent1].[product_name] END + N' ' + CASE WHEN ([Extent1].[product_code] IS NULL) THEN N'' ELSE [Extent1].[product_code] END AS [C3], 
        [Project1].[C1] AS [C4]
        FROM  [dbo].[products] AS [Extent1]
        LEFT OUTER JOIN  (SELECT 
            [Extent2].[prod_id] AS [prod_id], 
            [Extent2].[prod_img_thumb] AS [prod_img_thumb], 
            1 AS [C1]
            FROM [dbo].[products_images] AS [Extent2] ) AS [Project1] ON [Project1].[prod_id] = [Extent1].[id]
        WHERE 1 = [Extent1].[isActive]
    )  AS [Project2]
    ORDER BY [Project2].[id] ASC, [Project2].[C4] ASC

【问题讨论】:

也发布dynamicSearchQuery 好的,编辑一下 为什么这个问题要-1? @tchelidze 我已经用更多信息编辑了这个问题 为什么? :-) (如下所述,但为了完整起见) 【参考方案1】:

你可以引入一个新的对象,例如我们称之为ComplexProductDto,它应该与SQL返回的查询结果结构完全匹配,例如:

// Please adjust...
public class ComplexProductDto

    public int Id  get; set; 
    public int ProductDesc  get; set; 
    ...
    public string ProdImgThumb  get; set; 

现在数据将被展平和取消分组,包含重复的记录,您可以使用 Linq 在内存中进行分组。

var rawComplexData = db.Database.SqlQuery<ComplexProductDto>(dynamicSearchQuery).ToList(); 
var prodResult = rawComplexData
  .GroupBy(x => new
  
      x.Id,
      x.ProductDesc,
      // List all but Image...
  )
  .Select(x => new ComplexProductModel
  
      id = x.Key.Id,
      desc = x,Key.ProductDesc,
      .... // etc.
      images = x.Select(i => i.ProdImgThumb).ToList()
  );

代码可能不是 100% 正确,但您明白了。该技术是检索未分组的数据并将其分组回所需的结构。

【讨论】:

我也有同样的想法,但我真的想避免另一个步骤,如果实体可以自己做的话。我的意思是内置功能可以做到。我将等待替代方案的任何方式,如果没有更好的解决方案,我将接受您的回答。 这也引出了另一个问题,以防模型需要是通用的,然后呢? 1) db 是一个特定的数据上下文,它拥有所有实体、关系等的知识,但是通过使用db.Database,您基本上离开了该级别并进入原始访问。您基本上在实体框架数据库上下文之外进行操作。 2)“unflattening”技术特定于使用的对象,通用解决方案不是您想要构建的,您不想重新发明实体框架:-) 也许,更好解决方案的来源在于 为什么,绕过EF内置函数的目的是什么?否则,这将是一条更加崎岖不平的道路。 哎呀,这将是非常崎岖的道路:P

以上是关于使用原始 SQL 查询绑定复杂模型实体?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 原始 SQL 查询,具有多次出现的命名绑定

如何将参数绑定到模型上使用的 Laravel 中的原始数据库查询?

如何使用实体框架执行原始 SQL 查询而无需使用模型?

WPF数据绑定问题(很菜的)

Laravel 5 Eloquent:如何获取正在执行的原始 sql? (带有绑定数据)

octobercms数据库使用