原始 SQL 查询 (EF6)

通过实体框架,可使用 LINQ 和实体类进行查询。 但是,有时你可能希望使用原始 SQL 直接针对数据库运行查询。 这包括调用存储过程,这对于当前不支持映射到存储过程的 Code First 模型很有帮助。 本主题所介绍的方法同样适用于查询使用 Code First 和 EF 设计器创建的模型。

为实体编写 SQL 查询

DbSet 上的 SqlQuery 方法允许编写将返回实体实例的原始 SQL 查询。 返回的对象将由上下文跟踪,就像它们是由 LINQ 查询返回的一样。 例如:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs.SqlQuery("SELECT * FROM dbo.Blogs").ToList();
}

请注意,就像 LINQ 查询一样,查询在枚举结果之前不会执行 - 在上面的示例中,此操作通过调用 ToList 来完成。

出于两个原因,每当编写原始 SQL 查询时都应该小心。 首先,应编写查询以确保它仅返回真正属于所请求类型的实体。 例如,使用继承等功能时,很容易编写这样一个查询,它将创建属于错误 CLR 类型的实体。

其次,某些类型的原始 SQL 查询会暴露潜在的安全风险,尤其是围绕 SQL 注入式攻击。 确保以正确的方式在查询中使用参数,以防范此类攻击。

从存储过程加载实体

可使用 DbSet.SqlQuery 从存储过程的结果中加载实体。 例如,以下代码调用数据库中的 dbo.GetBlogs 过程:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs.SqlQuery("dbo.GetBlogs").ToList();
}

你也可以使用以下语法将参数传递给存储过程:

using (var context = new BloggingContext())
{
    var blogId = 1;

    var blogs = context.Blogs.SqlQuery("dbo.GetBlogById @p0", blogId).Single();
}

为非实体类型编写 SQL 查询

可使用 Database 类上的 SqlQuery 方法创建返回任何类型(包括基元类型)的实例的 SQL 查询。 例如:

using (var context = new BloggingContext())
{
    var blogNames = context.Database.SqlQuery<string>(
                       "SELECT Name FROM dbo.Blogs").ToList();
}

从 Database 上的 SqlQuery 返回的结果永远不会由上下文跟踪(即使对象是实体类型的实例)。

向数据库发送原始命令

可使用 Database 上的 ExecuteSqlCommand 方法将非查询命令发送到数据库。 例如:

using (var context = new BloggingContext())
{
    context.Database.ExecuteSqlCommand(
        "UPDATE dbo.Blogs SET Name = 'Another Name' WHERE BlogId = 1");
}

请注意,在从数据库加载或重载实体之前,使用 ExecuteSqlCommand 对数据库中的数据所做的任何更改对上下文都是不透明的。

输出参数

如果使用输出参数,则在完全读取结果之前,这些参数的值将不可用。 这是 DbDataReader 的基础行为所致;有关详细信息,请参阅使用 DataReader 检索数据