And*_*ykh 6 debugging entity-framework entity-framework-4
这是关于具体情况的一些主观问题.这个问题的主要目标是提醒我自己编写解决方案的代码.但是,如果已经有解决方案或替代方法,我想知道它.
我正在开发一个项目,我正在使用Entity Framework 4进行数据库访问.数据库设计是我无法控制的.该数据库是多年前设计的,在我看来,数据库设计不适合当前的数据库目的.这导致非常复杂的查询.
这是我第一次在项目中使用Entity Framework,但我在针对MS SQL Server的开发方面拥有丰富的经验.
我发现自己一次又一次地做的是:
说实话,我开始认为如果你不拥有数据库设计就不应该使用ORM.
除此之外,unescaping sql和替换参数的过程是我想要自动化的过程.我的目标是获得"裸",去参数化的sql,我可以在SSMS中运行.
这是我在配置文件中看到的以及我想要获得的结果的一个非常简单的示例.我的真实情况要复杂很多倍.
捕获:
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'
Run Code Online (Sandbox Code Playgroud)
期望的结果:
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])
Run Code Online (Sandbox Code Playgroud)
如果没有什么比这更好的话,我只是想编写代码来将第一类转换为第二类,我会在这里发布解决方案.但也许它已经由某人完成了?或者也许有一个分析器或其他东西,可以给我一些我可以在SSMS中部分执行的SQL代码?
所以这就是我最终的结果.几个笔记:
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));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)