我有一个带有SQL Server后端的WebAPI服务,它使用Entity Framework(代码优先)进行管理。我使用Linq查询从数据库中检索数据。由于我的一些API端点执行多个连接以获取数据,因此在生产中部署时发现了一些延迟。我读到使用ORM映射与直接SQL查询(存储过程),并得出结论,对于复杂查询,使用存储过程是最佳的。
我发现了一些文章,解释了如何使用以下代码从存储过程返回值:
// I have provided a function
<button onClick={ function(event){
this.onDeleteClick(event.target.value) }
} }>
<span>Remove</span>
</button>
但是,所有示例都涉及简单的context.Database.SqlQuery<T>(...)
查询,是的,我也遇到了多个SELECT
查询结果。但在这种情况下,它是2 SELECT
个查询。
在实际情况中,它可能超过2个选择查询,因为它可能涉及连接和其他代码。并且,在查询结束时,我们只会推断出返回预期数据的最终SELECT
查询。下面是一个示例代码来解释场景:
SELECT
如何从最后// Inside my stored procedure
Declare @XId uniqueidentifier
Declare @YId uniqueidentifier
// Some mockup queries. This can have JOINS and other complex codes in real code.
// Below code is made as simple as possible to explain the scenario
Select @XId=Id From Table1 Where Name = 'Name1'
Select @YId=Id From Table2 Where Code = 'Code1'
// This is the data, I am interested
Select * From Table3 Where Col1Id=@XId And Col2Id=@YId
个查询中获取行?
我做了一些研究,并认为由于存储过程支持很少,因此不可能使用EF。这可能在EF限制内完成,还是我需要回到ADO.NET呢?
任何帮助将不胜感激。
感谢。
答案 0 :(得分:1)
在阅读MSDN文章后,我以某种方式设法推断出了一个解决方案 - https://msdn.microsoft.com/en-us/data/jj691402.aspx。这就是我所做的。
我使用返回DbCommand.ExecuteReader()
的{{1}}执行存储过程。因为,我的兴趣点是最后一个DbDataReader
声明。我设法跳到SELECT
的最后一个结果集,然后使用DbCommandReader
将其转换为DTO
。
不确定是否有更好的可选项。暂时它有效。
更新:我终于切换到Dapper这是StackExchange的微型ORM。与EF相比,它可以显着提升性能。使用EF花费3秒的API调用现在可以在不到500毫秒的时间内返回数据。
感谢。
答案 1 :(得分:0)
由于您没有透露很多代码,我只能为您提供工作样本。
假设您拥有以下CodeFirst架构
class DbC : DbContext
{
public DbC()
{
}
public DbSet<Blog> Blogs { get; set; }
}
class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public List<Post> Posts { get; set; }
}
class Post
{
public int Id { get; set; }
public string Text { get; set; }
}
我假设驻留在数据库中的一些数据:
var tmp = new List<Blog>()
{
new Blog
{
Name = "Blog1",
Posts = new List<Post>()
{
new Post { Text = "Post1" },
new Post { Text = "Post2" },
new Post { Text = "Post3" },
}
},
new Blog
{
Name = "Blog2",
Posts = new List<Post>()
{
new Post { Text = "Post4" },
new Post { Text = "Post5" },
new Post { Text = "Post6" },
}
},
};
通过Posts
Blog.Name
的存储过程
CREATE PROCEDURE [dbo].[PostsRetrieverProc]
@BlogName NVARCHAR (MAX)
AS
Declare @BlogId int = 0
Select @BlogId=Id From [Blogs] Where Name = @BlogName
Select
b.Id [BlogId],
p.Id [PostId],
p.[Text] [PostText]
From [Blogs] b join [Posts] p On b.Id = p.Blog_Id
Where p.Blog_Id = @BlogId
GO
然后,您可以使用名称和类型与您的过程结果匹配的属性创建一个任意类
public class MyCustomReturnType
{
public int BlogId { get; set; }
public int PostId { get; set; }
public string PostText { get; set; }
}
并调用存储过程返回一些值
using (var db = new DbC())
{
var result = db.Database.SqlQuery<MyCustomReturnType>("dbo.PostsRetrieverProc @param1", new SqlParameter("param1", "Blog2"));
foreach (var item in result)
{
Console.WriteLine(item.PostText);
}
}
我的结果按预期输出:
Post4
Post5
Post6
这种方法有什么问题吗?
修改强>
由于您只需要存储过程的最后一个结果,因此最好重新设计SP而不是跳过中间结果。这可以使用With
clause来完成。请注意,此示例代码有点臃肿,因为我只使用博客ID并仍然与[Blogs]
一起加入以显示其可能的
CREATE PROCEDURE [dbo].[PostsRetrieverProc]
@BlogName NVARCHAR (MAX)
AS
With
BlogEntries (BlogId)
As
(Select Id BlogId From [Blogs] Where Name = @BlogName)
Select
b.Id [BlogId],
p.Id [PostId],
p.[Text] [PostText]
From BlogEntries e
join [Blogs] b On e.BlogId = b.Id
join [Posts] p On b.Id = p.Blog_Id
允许多次预先选择也很有意思:Can I use multiple "with"?
答案 2 :(得分:0)
不要只使用执行。
使用这个sql:
Insert into #tempTable
execute sp_executesql @SELECT