【问题标题】:EF Core 2.0 how to use SQL stored procedureEF Core 2.0 如何使用 SQL 存储过程
【发布时间】:2018-06-21 00:46:32
【问题描述】:

我是使用存储过程的 EF Core 2.0 的新手。

谁能帮助我如何在我的 EF Core 2.0 代码优先方法中使用存储过程?

在我之前的项目中,我有一个.edmx 模型文件,我使用的上下文如下:

public IEnumerable<UserResult> GetUserResults(Entities context)
{
    if (context == null) return new List<UserResult>();
    return context.spGetUsers().Where(u => u.IsDeleted == false);
}

上下文是:

public virtual ObjectResult<UserResult> spGetUsers()
{
    return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<UserResult>("spGetUsers");
}

谢谢

【问题讨论】:

    标签: stored-procedures entity-framework-core asp.net-core-2.0 entity-framework-core-migrations


    【解决方案1】:

    为了节省别人一个小时左右......

    ErikEJ 的回答完美无缺,但我需要先做一些额外的工作。

    在反向代码第一次迁移(到具有存储过程的现有数据库)之后,我遇到了一个问题,即现有数据库上的存储过程没有返回标准表(例如Blog 的列表),而是一个不同的类(例如BlogTitleAndSummary 的列表)不在数据库中(因此迁移)。

    这篇帖子说返回 must be an entity type,我不确定,但 Eriks 帖子的 another 为我指明了正确的方向。

    要让这个场景发挥作用:

    我创建了一个“BlogTitleAndSummary”类,将一个属性标记为[key]。

    例如

    public class BlogTitleAndSummary
    {
        [Key]
        public int BlogId { get; set; }
    
        public string Title { get; set; }
    
        public string ShortSummary { get; set; }
    }
    

    然后,我将它作为 DbSet 添加到上下文中,例如

    public partial class BloggingContext : DbContext
    {
        public BloggingContext()
        {
        }
    
        public BloggingContext(DbContextOptions<BloggingContext> options)
            : base(options)
        {
        }
    
        // Might be best to move these to another partial class, so they don't get removed in any updates.
        public virtual DbSet<BlogTitleAndSummary> BlogTitleAndSummary { get; set; }
    
        // Standard Tables
        public virtual DbSet<Blog> Blog { get; set; }
        ...
    }
    

    这使我能够使用以下语法来调用存储过程:

    注意:我已根据以下评论更新了此内容。使用 FromSql 方法中的参数。不要对此类sql queries 使用字符串插值。

    using (var ctx = new BloggingContext())
    {
    var dbResults = ctx.BlogTitleAndSummary.FromSql("EXEC dbo.get_bloggingSummary @UserId={0}", userId).ToList();
    }
    

    【讨论】:

    • 只是想让您和其他人意识到您的特定示例string query = @"EXEC [dbo].[get_bloggingSummary] @User = N'" + userId + @"'; 是不安全的,无论您的存储过程编写得多么好,您不应忽略该警告。查询应通过单独传入参数FromSql("exec dbo.get_bloggingSummary {0}", userId) 或使用字符串插值FromSql($"exec dbo.get_bloggingSummary {userId}") 进行参数化,EF Core 将自动为您进行参数化。
    • @sgbj - 谢谢。我已经按照您的 cmets 更新了示例(以及我自己的代码!)。它确实消除了有关 sql 注入攻击的警告。
    【解决方案2】:

    您可以使用 FromSQL 方法:

    var blogs = context.Blogs
        .FromSql("EXECUTE dbo.GetMostPopularBlogs")
        .ToList();
    

    https://docs.microsoft.com/en-us/ef/core/querying/raw-sql

    【讨论】:

    • 非常感谢。因此,在执行所有迁移之后,我只需要在数据库中创建存储过程。对吗?
    • 是的,或者您可以在迁移期间使用 Sql() 方法创建它们(编辑迁移)
    • 非常感谢。很抱歉在同一行再问你一件事。目前我的“用户结果”不是数据库中的一个实体。它是[未映射]。在那种情况下,我该如何执行查询?与您的示例 context.Blogs 一样,我没有 context.UserResults。谢谢
    • 阅读文档,你会发现这是目前不可能的
    • 如果您指的是查询类型的使用,此功能现在在 EF Core 2.1 中:docs.microsoft.com/en-us/ef/core/modeling/query-types
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多