调试实体框架查询
这是一个关于具体情况的主观问题。对我来说,这个问题的主要目标是提醒自己编写解决方案。但是,如果已经有解决方案或替代方法,我想知道。
我正在开发一个项目,并使用 Entity Framework 4 进行数据库访问。数据库设计是我无法控制的。该数据库是多年前设计的,在我看来,该数据库设计不适合当前的数据库用途。这会导致非常复杂的查询。
这是我第一次在项目中使用实体框架,但我在针对 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 代码?
This is a bit of subjective question about a specific situation. Main goal for this question for me is to remind my self to code up the solution. However if there is already a solution, or an alternate approach, I would like to know it.
I'm working on a project and I'm using Entity Framework 4 for database access. The database design is something that I don't have control over. The database was designed many years ago, and in my opinion the database design does not fit for the current database purposes. This results in very complicated queries.
This is the first time I'm using Entity Framework in a project, but I have extensive experience in development against MS SQL Server.
What I found myself doing again and again is this:
- I write a complex L2E query. The query either slow or returns wrong results
- I'm looking at my L2E query and I have absolutely no idea how to improve it
- I fire up SQL Profiler and capture the SQL that EF generated from my query
- I want to execute part of that sql to identify the part of the query that is giving problems
- The query comes through as sp_executesql with a dozen of parameters, because if a parameter is used 3 times in a query, L2E creates 3 parameters and passes to all of them the same value. Same deal with every parameter.
- Now I have to extract the SQL from sp_executesql, unescape all escaped apostrophes, and substitute every parameter in the query with its value
- After this is done I finally can run parts of the query and pin-point the problem.
- I go back to my L2E code, change it to fix the problem I found and the cycle repeats.
To be honest, I'm starting thinking that one should not use an ORM if you don't own database design.
This aside, the process of unescaping the sql and substituting the parameters is the one that I want to automate. The goal is to get 'naked', de-parametrized sql, that I can run in SSMS.
This a very simple example of what I see in the profile and what I want to get in result. My real cases are many times more complex.
The capture:
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'
Desired result:
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])
I'm just going to write code to convert the likes of first to the likes of second if there is nothing better, I'll post the solution here. But maybe it's already done by someone? Or maybe there is a profiler or something, that can give me sql code I can execute partially in SSMS?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这就是我最终得到的结果。一些注意事项:
So here is what I ended up with. A couple of notes:
嗯,也许这会有所帮助。 MSVS 2010 具有 IntelliTrace。每次 EF 进行查询时,都会有一个带有查询的 ADO.Net 事件
Well,may be this will be helpfull. MSVS 2010 has IntelliTrace. Every time when EF make a query there is an ADO.Net Event with a query