Làm cách nào để tôi xem SQL được tạo bởi khung thực thể?
(Trong trường hợp cụ thể của tôi, tôi đang sử dụng nhà cung cấp mysql - nếu có vấn đề)
Làm cách nào để tôi xem SQL được tạo bởi khung thực thể?
(Trong trường hợp cụ thể của tôi, tôi đang sử dụng nhà cung cấp mysql - nếu có vấn đề)
Câu trả lời:
Bạn có thể làm như sau:
IQueryable query = from x in appEntities
where x.id == 32
select x;
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
hoặc trong EF6:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query)
.ToTraceString();
Điều đó sẽ cung cấp cho bạn SQL đã được tạo.
.Single()
đối tượng của bạn không còn nữa IQueryable
tôi đoán.
result
để System.Data.Entity.Infrastructure.DbQuery<T>
, sau đó nhận được tài sản nội bộ InternalQuery
như (System.Data.Entity.Internal.Linq.InternalQuery<T>)
, và chỉ khi đó, sử dụngToTraceString()
result.ToString()
Đối với những người sử dụng Entity Framework 6 trở lên, nếu bạn muốn xem SQL đầu ra trong Visual Studio (như tôi đã làm), bạn phải sử dụng chức năng ghi nhật ký / chặn mới.
Thêm dòng sau sẽ nhổ SQL được tạo ra (cùng với các chi tiết liên quan đến thực thi bổ sung) trong bảng đầu ra Visual Studio:
using (MyDatabaseEntities context = new MyDatabaseEntities())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
// query the database using EF here.
}
Thông tin thêm về đăng nhập vào EF6 trong loạt blog tiện lợi này: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Lưu ý: Đảm bảo bạn đang chạy dự án của mình ở chế độ DEBUG.
Bắt đầu với EF6.1, bạn có thể sử dụng Thiết bị chặn để đăng ký bộ ghi cơ sở dữ liệu. Xem các chương "Đánh chặn" và "Ghi nhật ký hoạt động cơ sở dữ liệu" vào một tệp tại đây
<interceptors>
<interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework">
<parameters>
<parameter value="C:\Temp\LogOutput.txt"/>
<parameter value="true" type="System.Boolean"/>
</parameters>
</interceptor>
</interceptors>
Nếu bạn đang sử dụng DbContext, bạn có thể thực hiện các thao tác sau để nhận SQL:
var result = from i in myContext.appEntities
select new Model
{
field = i.stuff,
};
var sql = result.ToString();
ToString()
sẽ cung cấp cho bạn truy vấn với các biến trong nó, như p__linq__0
, thay vì các giá trị chính thức (ví dụ: 34.563 thay vì p__linq__0
)
Áp dụng cho EF 6.0 trở lên: Dành cho những bạn muốn biết thêm về chức năng ghi nhật ký và thêm vào một số câu trả lời đã được đưa ra.
Bất kỳ lệnh nào được gửi từ EF đến cơ sở dữ liệu bây giờ có thể được ghi lại. Để xem các truy vấn được tạo từ EF 6.x, hãy sử dụngDBContext.Database.Log property
Những gì được ghi lại
- SQL for all different kinds of commands. For example: - Queries, including normal LINQ queries, eSQL queries, and raw queries from methods such as SqlQuery. - Inserts, updates, and deletes generated as part of SaveChanges - Relationship loading queries such as those generated by lazy loading - Parameters - Whether or not the command is being executed asynchronously - A timestamp indicating when the command started executing - Whether or not the command completed successfully, failed by throwing an exception, or, for async, was canceled - Some indication of the result value - The approximate amount of time it took to execute the command. Note that this is the time from sending the command to getting the result object back. It does not include time to read the results.
Thí dụ:
using (var context = new BlogContext())
{
context.Database.Log = Console.Write;
var blog = context.Blogs.First(b => b.Title == "One Unicorn");
blog.Posts.First().Title = "Green Eggs and Ham";
blog.Posts.Add(new Post { Title = "I do not like them!" });
context.SaveChangesAsync().Wait();
}
Đầu ra:
SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title]
FROM [dbo].[Blogs] AS [Extent1]
WHERE (N'One Unicorn' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 4 ms with result: SqlDataReader
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title],
[Extent1].[BlogId] AS [BlogId]
FROM [dbo].[Posts] AS [Extent1]
WHERE [Extent1].[BlogId] = @EntityKeyValue1
-- EntityKeyValue1: '1' (Type = Int32)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader
UPDATE [dbo].[Posts]
SET [Title] = @0
WHERE ([Id] = @1)
-- @0: 'Green Eggs and Ham' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 12 ms with result: 1
INSERT [dbo].[Posts]([Title], [BlogId])
VALUES (@0, @1)
SELECT [Id]
FROM [dbo].[Posts]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'I do not like them!' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader
Để đăng nhập vào một tập tin bên ngoài:
using (var context = new BlogContext())
{
using (var sqlLogFile = new StreamWriter("C:\\temp\\LogFile.txt"))
{
context.Database.Log = sqlLogFile.Write;
var blog = context.Blogs.First(b => b.Title == "One Unicorn");
blog.Posts.First().Title = "Green Eggs and Ham";
context.SaveChanges();
}
}
Thêm thông tin ở đây: Ghi nhật ký và chặn hoạt động cơ sở dữ liệu
Bạn có thể làm như sau trong EF 4.1:
var result = from x in appEntities
where x.id = 32
select x;
System.Diagnostics.Trace.WriteLine(result .ToString());
Điều đó sẽ cung cấp cho bạn SQL đã được tạo.
ToString()
đầu ra là không gian tên của loại tùy chỉnh đó. Ví dụ: nếu mã ở trên là select new CustomType { x = x.Name }
, giá trị được trả về sẽ giống như Company.Models.CustomType
thay vì SQL được tạo.
System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]
cho tôi.
Câu trả lời của tôi giải quyết lõi EF . Tôi tham khảo vấn đề github này và các tài liệu về cấu hìnhDbContext
:
Đơn giản
Ghi đè OnConfiguring
phương thức của DbContext
lớp của bạn ( YourCustomDbContext
) như được hiển thị ở đây để sử dụng ConsoleLoggerProvider; truy vấn của bạn sẽ đăng nhập vào bảng điều khiển:
public class YourCustomDbContext : DbContext
{
#region DefineLoggerFactory
public static readonly LoggerFactory MyLoggerFactory
= new LoggerFactory(new[] {new ConsoleLoggerProvider((_, __) => true, true)});
#endregion
#region RegisterLoggerFactory
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLoggerFactory(MyLoggerFactory); // Warning: Do not create a new ILoggerFactory instance each time
#endregion
}
Phức tạp
Trường hợp phức tạp này tránh trọng các DbContext
OnConfiguring
phương pháp. , điều không được khuyến khích trong các tài liệu: "Cách tiếp cận này không cho vay để thử nghiệm, trừ khi các thử nghiệm nhắm vào cơ sở dữ liệu đầy đủ."
Trường hợp phức tạp này sử dụng:
IServiceCollection
trong Startup
lớp ConfigureServices
phương pháp (thay vì trọng các OnConfiguring
phương pháp; lợi ích là một khớp nối lỏng lẻo giữa DbContext
và ILoggerProvider
bạn muốn sử dụng)ILoggerProvider
(thay vì sử dụng ConsoleLoggerProvider
triển khai được hiển thị ở trên; lợi ích là việc triển khai của chúng tôi cho thấy cách chúng tôi sẽ đăng nhập vào Tệp (Tôi không thấy Nhà cung cấp ghi nhật ký tệp được vận chuyển với EF Core ))Như thế này:
public class Startup
public void ConfigureServices(IServiceCollection services)
{
...
var lf = new LoggerFactory();
lf.AddProvider(new MyLoggerProvider());
services.AddDbContext<YOUR_DB_CONTEXT>(optionsBuilder => optionsBuilder
.UseSqlServer(connection_string)
//Using the LoggerFactory
.UseLoggerFactory(lf));
...
}
}
Đây là việc triển khai MyLoggerProvider
(và bổ sung MyLogger
nhật ký của nó vào Tệp mà bạn có thể định cấu hình; các truy vấn EF Core của bạn sẽ xuất hiện trong tệp.)
public class MyLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new MyLogger();
}
public void Dispose()
{ }
private class MyLogger : ILogger
{
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
File.AppendAllText(@"C:\temp\log.txt", formatter(state, exception));
Console.WriteLine(formatter(state, exception));
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
}
}
Có hai cách:
ToTraceString()
. Bạn có thể thêm nó vào cửa sổ đồng hồ của mình và đặt điểm dừng để xem truy vấn sẽ ở điểm nào cho bất kỳ truy vấn LINQ nào.tail -f
. Bạn có thể tìm hiểu thêm về các cơ sở ghi nhật ký của MySQL trong tài liệu chính thức . Đối với SQL Server, cách dễ nhất là sử dụng trình lược tả SQL Server đi kèm.Để có truy vấn luôn tiện dụng, không cần thay đổi mã, hãy thêm mã này vào DbContext của bạn và kiểm tra nó trên cửa sổ đầu ra trong phòng thu trực quan.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.Log = (query)=> Debug.Write(query);
}
Tương tự như câu trả lời @Matt Nibecker, nhưng với điều này, bạn không phải thêm nó vào mã hiện tại của mình, mỗi khi bạn cần truy vấn.
SQL Management Studio => Công cụ => Trình hồ sơ SQL Server
Tệp => Dấu vết mới ...
Sử dụng Mẫu => Trống
Lựa chọn sự kiện => T-SQL
Kiểm tra Lefthandside cho: SP.StmtComplete
Bộ lọc cột có thể được sử dụng để chọn một ApplicationName hoặc DatabaseName cụ thể
Bắt đầu hồ sơ đó chạy sau đó kích hoạt truy vấn.
Nhấn vào đây để biết thông tin nguồn
Vâng, tôi đang sử dụng Express profiler cho mục đích đó vào lúc này, nhược điểm là nó chỉ hoạt động cho MS SQL Server. Bạn có thể tìm thấy công cụ này tại đây: https://expressprofiler.codeplex.com/
IQueryable query = from x in appEntities
where x.id = 32
select x;
var queryString = query.ToString();
Sẽ trả về truy vấn sql. Làm việc bằng cách sử dụng datacontext của EntityFramework 6
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable
1 [System.Linq.IGrouping 2[System.Int32,String]]
thay vì truy vấn thực tế. Tôi đang thiếu một cái gì đó hoặc bạn đã quên đề cập đến một cái gì đó?
Tôi đang thực hiện kiểm tra tích hợp và cần điều này để gỡ lỗi câu lệnh SQL được tạo trong Entity Framework Core 2.1, vì vậy tôi sử dụng DebugLoggerProvider
hoặc ConsoleLoggerProvider
tương tự như vậy:
[Fact]
public async Task MyAwesomeTest
{
//setup log to debug sql queries
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new DebugLoggerProvider());
loggerFactory.AddProvider(new ConsoleLoggerProvider(new ConsoleLoggerSettings()));
var builder = new DbContextOptionsBuilder<DbContext>();
builder
.UseSqlServer("my connection string") //"Server=.;Initial Catalog=TestDb;Integrated Security=True"
.UseLoggerFactory(loggerFactory);
var dbContext = new DbContext(builder.Options);
........
Đây là một đầu ra mẫu từ bảng điều khiển Visual Studio:
Necromance.
Trang này là kết quả tìm kiếm đầu tiên khi tìm kiếm giải pháp cho bất kỳ .NET Framework nào, vì vậy đây là dịch vụ công cộng, cách thức thực hiện trong EntityFramework Core (cho .NET Core 1 & 2):
var someQuery = (
from projects in _context.projects
join issues in _context.issues on projects.Id equals issues.ProjectId into tmpMapp
from issues in tmpMapp.DefaultIfEmpty()
select issues
) //.ToList()
;
// string sql = someQuery.ToString();
// string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions.ToSql(someQuery);
// string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions1.ToSql(someQuery);
// using Microsoft.EntityFrameworkCore;
string sql = someQuery.ToSql();
System.Console.WriteLine(sql);
Và sau đó là các phương thức mở rộng này (IQueryableExtensions1 cho .NET Core 1.0, IQueryableExtensions cho .NET Core 2.0):
using System;
using System.Linq;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Remotion.Linq.Parsing.Structure;
namespace Microsoft.EntityFrameworkCore
{
// /programming/1412863/how-do-i-view-the-sql-generated-by-the-entity-framework
// http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/
public static class IQueryableExtensions
{
private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields
.First(x => x.Name == "_queryCompiler");
private static readonly PropertyInfo NodeTypeProviderField =
QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider");
private static readonly MethodInfo CreateQueryParserMethod =
QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser");
private static readonly FieldInfo DataBaseField =
QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly PropertyInfo DatabaseDependenciesField =
typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies");
public static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class
{
if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>))
{
throw new ArgumentException("Invalid query");
}
var queryCompiler = (QueryCompiler) QueryCompilerField.GetValue(query.Provider);
var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler);
var parser = (IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider});
var queryModel = parser.GetParsedQuery(query.Expression);
var database = DataBaseField.GetValue(queryCompiler);
var databaseDependencies = (DatabaseDependencies) DatabaseDependenciesField.GetValue(database);
var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
var sql = modelVisitor.Queries.First().ToString();
return sql;
}
}
public class IQueryableExtensions1
{
private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo()
.DeclaredFields
.First(x => x.Name == "_queryCompiler");
private static readonly PropertyInfo NodeTypeProviderField =
QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider");
private static readonly MethodInfo CreateQueryParserMethod =
QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser");
private static readonly FieldInfo DataBaseField =
QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly FieldInfo QueryCompilationContextFactoryField = typeof(Database).GetTypeInfo()
.DeclaredFields.Single(x => x.Name == "_queryCompilationContextFactory");
public static string ToSql<TEntity>(IQueryable<TEntity> query) where TEntity : class
{
if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>))
{
throw new ArgumentException("Invalid query");
}
var queryCompiler = (IQueryCompiler) QueryCompilerField.GetValue(query.Provider);
var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler);
var parser =
(IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider});
var queryModel = parser.GetParsedQuery(query.Expression);
var database = DataBaseField.GetValue(queryCompiler);
var queryCompilationContextFactory =
(IQueryCompilationContextFactory) QueryCompilationContextFactoryField.GetValue(database);
var queryCompilationContext = queryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
var sql = modelVisitor.Queries.First().ToString();
return sql;
}
}
}
var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
Trong trường hợp của tôi cho EF 6+, thay vì sử dụng điều này trong Cửa sổ ngay lập tức để tìm chuỗi truy vấn:
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();
Cuối cùng tôi đã phải sử dụng điều này để nhận lệnh SQL được tạo:
var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();
Tất nhiên chữ ký loại ẩn danh của bạn có thể khác nhau.
HTH.
Tôi vừa mới làm điều này:
IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);
Và kết quả hiển thị trong Kết quả :
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Code] AS [Code],
[Extent1].[Name] AS [Name],
[Extent2].[Id] AS [Id1],
[Extent2].[FileName] AS [FileName],
FROM [dbo].[Products] AS [Extent1]
INNER JOIN [dbo].[PersistedFiles] AS [Extent2] ON [Extent1].[PersistedFileId] = [Extent2].[Id]
WHERE [Extent1].[Id] = @p__linq__0
Đối với tôi, sử dụng EF6 và Visual Studio 2015 tôi đã nhập vào query
cửa sổ ngay lập tức và nó đã cho tôi Báo cáo SQL được tạo
Nếu bạn muốn có các giá trị tham số (không chỉ @p_linq_0
mà cả giá trị của chúng), bạn có thể sử dụng IDbCommandInterceptor
và thêm một số ghi nhật ký vào ReaderExecuted
phương thức.
Trong khi có câu trả lời tốt ở đây, không ai giải quyết vấn đề của tôi hoàn toàn (Tôi muốn có được toàn bộ câu lệnh SQL, bao gồm cả thông số , từ DbContext từ bất kỳ IQueryable. Các mã sau đây làm việc đó. Đó là một sự kết hợp của các đoạn mã từ Google. Tôi đã chỉ thử nghiệm nó với EF6 + .
Chỉ là một bên, nhiệm vụ này đã đưa tôi đi lâu hơn tôi nghĩ nó sẽ. Trừu tượng hóa trong Entity Framework là một chút, IMHO.
Đầu tiên là sử dụng. Bạn sẽ cần một tham chiếu rõ ràng đến 'System.Data.Entity.dll'.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Reflection;
Lớp sau đây chuyển đổi một IQueryable thành DataTable. Sửa đổi theo nhu cầu của bạn có thể là:
public class EntityFrameworkCommand
{
DbContext Context;
string SQL;
ObjectParameter[] Parameters;
public EntityFrameworkCommand Initialize<T>(DbContext context, IQueryable<T> query)
{
Context = context;
var dbQuery = query as DbQuery<T>;
// get the IInternalQuery internal variable from the DbQuery object
var iqProp = dbQuery.GetType().GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var iq = iqProp.GetValue(dbQuery, null);
// get the ObjectQuery internal variable from the IInternalQuery object
var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var objectQuery = oqProp.GetValue(iq, null) as ObjectQuery<T>;
SQL = objectQuery.ToTraceString();
Parameters = objectQuery.Parameters.ToArray();
return this;
}
public DataTable GetData()
{
DataTable dt = new DataTable();
var connection = Context.Database.Connection;
var state = connection.State;
if (!(state == ConnectionState.Open))
connection.Open();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = SQL;
cmd.Parameters.AddRange(Parameters.Select(p => new SqlParameter("@" + p.Name, p.Value)).ToArray());
using (var da = DbProviderFactories.GetFactory(connection).CreateDataAdapter())
{
da.SelectCommand = cmd;
da.Fill(dt);
}
}
if (!(state == ConnectionState.Open))
connection.Close();
return dt;
}
}
Để sử dụng, chỉ cần gọi nó như dưới đây:
var context = new MyContext();
var data = ....//Query, return type can be anonymous
.AsQueryable();
var dt = new EntityFrameworkCommand()
.Initialize(context, data)
.GetData();
Hầu hết các câu trả lời ở đây là dành riêng cho EF6. Đây là một trong những bạn vẫn đang sử dụng EF4.
Phương pháp này thay thế @p__linq__0
/ etc. tham số với các giá trị thực của chúng, vì vậy bạn chỉ cần sao chép và dán đầu ra vào SSMS và chạy hoặc gỡ lỗi nó.
/// <summary>
/// Temporary debug function that spits out the actual SQL query LINQ is generating (with parameters)
/// </summary>
/// <param name="q">IQueryable object</param>
private string Debug_GetSQLFromIQueryable<T>(IQueryable<T> q)
{
System.Data.Objects.ObjectQuery oq = (System.Data.Objects.ObjectQuery)q;
var result = oq.ToTraceString();
List<string> paramNames = new List<string>();
List<string> paramVals = new List<string>();
foreach (var parameter in oq.Parameters)
{
paramNames.Add(parameter.Name);
paramVals.Add(parameter.Value == null ? "NULL" : ("'" + parameter.Value.ToString() + "'"));
}
//replace params in reverse order, otherwise @p__linq__1 incorrectly replaces @p__linq__10 for instance
for (var i = paramNames.Count - 1; i >= 0; i--)
{
result = result.Replace("@" + paramNames[i], paramVals[i]);
}
return result;
}