gpt4 book ai didi

调试 Entity Framework 查询

转载 作者:行者123 更新时间:2023-12-03 17:07:02 25 4
gpt4 key购买 nike

这是关于特定情况的一些主观问题。对我来说,这个问题的主要目标是提醒自己编写解决方案。但是,如果已经有解决方案或替代方法,我想知道它。

我正在做一个项目,我正在使用 Entity Framework 4 进行数据库访问。数据库设计是我无法控制的。数据库是多年前设计的,在我看来,数据库设计不适合当前的数据库用途。这会导致非常复杂的查询。

这是我第一次在项目中使用 Entity Framework ,但我在针对 MS SQL Server 的开发方面拥有丰富的经验。

我发现自己一次又一次地做的是:

  • 我写了一个复杂的 L2E 查询。查询缓慢或返回错误结果
  • 我正在查看我的 L2E 查询,但我完全不知道如何改进它
  • 我启动 SQL Profiler 并捕获 EF 从我的查询中生成的 SQL
  • 我想执行该 sql 的一部分来识别出现问题的查询部分
  • 查询以带有十几个参数的 sp_executesql 形式出现,因为如果一个参数在查询中使用 3 次,L2E 会创建 3 个参数并将相同的值传递给所有参数。对每个参数进行相同的处理。
  • 现在我必须从 sp_executesql 中提取 SQL,取消转义所有转义的撇号,并将查询中的每个参数替换为其值
  • 完成此操作后,我终于可以运行部分查询并查明问题所在。
  • 我回到我的 L2E 代码,更改它以解决我发现的问题,然后循环重复。

  • 老实说,我开始认为如果您不拥有数据库设计,就不应该使用 ORM。

    除此之外,取消转义 sql 并替换参数的过程是我想要自动化的过程。目标是获得可以在 SSMS 中运行的“裸”、去参数化的 sql。

    这是一个非常简单的示例,说明了我在配置文件中看到的内容以及我想要得到的结果。我的真实案例要复杂很多倍。

    捕获:
    exec sp_executesql N'SELECT 
    [Extent1].[ProductName] AS [ProductName]
    FROM [dbo].[Products] AS [Extent1]
    INNER JOIN [dbo].[Categories] AS [Extent2] ON [Extent1].[CategoryID] = [Extent2].[CategoryID]
    WHERE ([Extent1].[UnitPrice] > @p__linq__0) AND ([Extent2].[CategoryName] = @p__linq__1) AND (N''Chang'' <> [Extent1].[ProductName])',N'@p__linq__0 decimal(1,0),@p__linq__1 nvarchar(4000)',@p__linq__0=1,@p__linq__1=N'Beverages'

    期望的结果:
    SELECT 
    [Extent1].[ProductName] AS [ProductName]
    FROM [dbo].[Products] AS [Extent1]
    INNER JOIN [dbo].[Categories] AS [Extent2] ON [Extent1].[CategoryID] = [Extent2].[CategoryID]
    WHERE ([Extent1].[UnitPrice] > 1) AND ([Extent2].[CategoryName] = N'Beverages') AND (N'Chang' <> [Extent1].[ProductName])

    如果没有更好的方法,我将编写代码将第一类转换为第二类,我将在此处发布解决方案。但也许它已经由某人完成了?或者也许有一个分析器或其他东西,可以给我可以在 SSMS 中部分执行的 sql 代码?

    最佳答案

    所以这就是我最终的结果。几点注意事项:

  • 这在 100% 的情况下不会起作用,但这对我来说已经足够了
  • 在可用性方面有很多需要改进的地方。目前我在桌面上放了一个编译后的二进制文件的快捷方式,剪切要转换为剪贴板的文本,双击快捷方式并粘贴结果。

  • using System;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;

    namespace EFC
    {
    static class Program
    {
    [STAThread]
    static void Main()
    {
    try
    {
    string input = Clipboard.GetText();
    const string header = "exec sp_executesql N'";

    CheckValidInput(input.StartsWith(header), "Input does not start with {0}", header);

    // Find part of the statement that constitutes whatever sp_executesql has to execute
    int bodyStartIndex = header.Length;
    int bodyEndIndex = FindClosingApostroph(input, bodyStartIndex);

    CheckValidInput(bodyEndIndex > 0, "Unable to find closing \"'\" in the body");

    string body = input.Substring(bodyStartIndex, bodyEndIndex - bodyStartIndex);

    // Unescape 's
    body = body.Replace("''", "'");

    // Work out where the paramters are
    int blobEndIndex = FindClosingApostroph(input, bodyEndIndex + 4);
    CheckValidInput(bodyEndIndex > 0, "Unable to find closing \"'\" in the params");

    string ps = input.Substring(blobEndIndex);

    // Reverse, so that P__linq_2 does not get substituted in p__linq_20
    Regex regexEf = new Regex(@"(?<name>@p__linq__(?:\d+))=(?<value>(?:.+?)((?=,@p)|($)))", RegexOptions.RightToLeft);
    Regex regexLinqToSql = new Regex(@"(?<name>@p(?:\d+))=(?<value>(?:.+?)((?=,@p)|($)))", RegexOptions.RightToLeft);

    MatchCollection mcEf = regexEf.Matches(ps);
    MatchCollection mcLinqToSql = regexLinqToSql.Matches(ps);
    MatchCollection mc = mcEf.Count > 0 ? mcEf : mcLinqToSql;

    // substitutes parameters in the statement with their values
    foreach (Match m in mc)
    {
    string name = m.Groups["name"].Value;
    string value = m.Groups["value"].Value;
    body = body.Replace(name, value);
    }

    Clipboard.SetText(body);
    MessageBox.Show("Done!", "CEF");

    }
    catch (ApplicationException ex)
    {
    MessageBox.Show(ex.Message, "Error");
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message, "Error");
    MessageBox.Show(ex.StackTrace, "Error");
    }
    }

    static int FindClosingApostroph(string input, int bodyStartIndex)
    {
    for (int i = bodyStartIndex; i < input.Length; i++)
    {
    if (input[i] == '\'' && i + 1 < input.Length)
    {
    if (input[i + 1] != '\'')
    {
    return i;
    }
    i++;
    }
    }

    return -1;
    }

    static void CheckValidInput(bool isValid, string message, params object[] args)
    {
    if (!isValid)
    {
    throw new ApplicationException(string.Format(message, args));
    }
    }
    }
    }

    关于调试 Entity Framework 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6054484/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com