原始 SQL 运行 与 Entity Framework 核心上下文相比如何?
How is raw SQL run against an Entity Framework Core context?
我已经使用 Entity Framework 很长时间了,但在极端情况下我需要使用 SQL。我想知道我是否可以为此使用现有的 Entity Framework 核心上下文。这是我目前拥有的,但是 queryResults 变量包含一个“-1”值,而不是学生列表,在 运行 之后:
string tableName = "Students";
var queryResults = db.Database.ExecuteSqlRaw(@"SELECT * FROM {0}", tableName);
有什么想法吗?
- Entity Framework 核心 3.1
- .NET 核心 3.1
- Linq-to-SQL
"I was wondering if I could use my existing Entity Framework Core context for this or not":
是的,您可以使用 existing databaseContext
,但您必须在 dbContext Entity
上执行该查询,请参见下面的示例:
var sqlCommand = $"SELECT * FROM Students";
var executeSQL = await _context.Students.FromSqlRaw(sqlCommand).ToListAsync();
return Ok(executeSQL);
Output:
Note:
As you can see I am executing sqlCommand
on Students
dbContext
this is valid. But using DbContext
you cannot pass the
table name dynamically. You must need to define it explicitly
.
希望以上步骤对您有相应的指导,您可以看看official document for more details here
Update Using Ado.Net Connection:
using (var connection = _context.Database.GetDbConnection())
{
connection.Open();
var tableName = "Students";
List<Student> _listStudent = new List<Student>();
var command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = string.Format("SELECT * FROM [{0}];", tableName);
SqlDataReader reader = (SqlDataReader)command.ExecuteReader();
while (reader.Read())
{
var student = new Student(); // You have to bind dynamic property here based on your table entities
student.FirstName = reader["FirstName"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
student.LastName = reader["LastName"].ToString();
_listStudent.Add(student);
}
reader.Close();
command.Dispose();
connection.Close();
}
有可能;我只是为了一个宠物项目而不得不这样做。
您需要引用 Microsoft.EntityFrameworkCore.Relational NuGet。
ConsoleApp 示例:
Program.cs
using System.Collections.Generic;
namespace EfDirectSql
{
class Program
{
/*
* written: VS2019 .Net Core 3.1 Console App
*
* used nugets:
*
* Microsoft.EntityFrameworkCore.SqlServer 3.1.0
* Microsoft.EntityFrameworkCore.Relational 3.1.0
*
*/
static void Main(string[] args)
{
// attention: supply your database server name
ApplicationContext context = new ApplicationContext("?YOURSERVER?", "Master");
// note: leveraging included extension methods for the dbContext class.
object scalarResult = context.ExecuteScalar("SELECT COUNT(1) FROM Master.dbo.SysObjects");
object nonQueryResult = context.ExecuteNonQuery("SELECT * FROM Master.dbo.SysObjects"); // likely your -1
IEnumerable<SysObject> readerResult = context.ExecuteReader<SysObject>("SELECT * FROM Master.dbo.SysObjects");
}
}
}
ApplicationContext.cs
using Microsoft.EntityFrameworkCore;
namespace EfDirectSql
{
public class ApplicationContext
: DbContext
{
public ApplicationContext(string serverName, string catalogName)
{
this.ServerName = serverName;
this.CatalogName = catalogName;
}
public readonly string ServerName;
public readonly string CatalogName;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer($"Data Source={this.ServerName};Initial Catalog={this.CatalogName};Integrated Security=true;");
base.OnConfiguring(optionsBuilder);
}
}
}
DbContextExtensions.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
namespace EfDirectSql
{
public static class DbContextExtensions
{
public static object ExecuteScalar
(
this DbContext context,
string sql
)
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
object result = null;
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
result = command.ExecuteScalar();
}
finally
{
connection.Close();
}
return result;
}
public static int ExecuteNonQuery
(
this DbContext context,
string sql
)
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
int result;
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
result = command.ExecuteNonQuery();
// likely the -1
}
finally
{
connection.Close();
}
return result;
}
public static IEnumerable<TType> ExecuteReader<TType>
(
this DbContext context,
string sql
)
where TType : class, new()
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
IEnumerable<TType> result = new List<TType>();
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
IDataReader reader = command.ExecuteReader(CommandBehavior.Default);
result = Convert<TType>(reader);
}
finally
{
connection.Close();
}
return result;
}
private static IEnumerable<TType> Convert<TType>(IDataReader reader)
where TType : class, new()
{
List<PropertyInfo> properties = typeof(TType)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite)
.ToList();
IList<TType> instances = new List<TType>();
while (reader.Read())
{
TType instance = new TType();
properties
.ForEach
(p =>
// for the purposes of the example, this works - could be outliers.
p.SetValue(instance, reader[p.Name] == DBNull.Value ? null : reader[p.Name])
);
instances.Add(instance);
}
return instances;
}
}
}
SysObject.cs
namespace EfDirectSql
{
// shortened represenation of the MS-SQL sysobject table
public class SysObject
{
public string name { get; set; }
public int id { get; set; }
public string xtype { get; set; }
public int uid { get; set; }
public int info { get; set; }
public int status { get; set; }
// the rest are not needed for a demo.
}
}
我已经使用 Entity Framework 很长时间了,但在极端情况下我需要使用 SQL。我想知道我是否可以为此使用现有的 Entity Framework 核心上下文。这是我目前拥有的,但是 queryResults 变量包含一个“-1”值,而不是学生列表,在 运行 之后:
string tableName = "Students";
var queryResults = db.Database.ExecuteSqlRaw(@"SELECT * FROM {0}", tableName);
有什么想法吗?
- Entity Framework 核心 3.1
- .NET 核心 3.1
- Linq-to-SQL
"I was wondering if I could use my existing Entity Framework Core context for this or not":
是的,您可以使用 existing databaseContext
,但您必须在 dbContext Entity
上执行该查询,请参见下面的示例:
var sqlCommand = $"SELECT * FROM Students";
var executeSQL = await _context.Students.FromSqlRaw(sqlCommand).ToListAsync();
return Ok(executeSQL);
Output:
Note:
As you can see I am executingsqlCommand
onStudents
dbContext
this is valid. But usingDbContext
you cannot pass the table name dynamically. You must need todefine it explicitly
.
希望以上步骤对您有相应的指导,您可以看看official document for more details here
Update Using Ado.Net Connection:
using (var connection = _context.Database.GetDbConnection())
{
connection.Open();
var tableName = "Students";
List<Student> _listStudent = new List<Student>();
var command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = string.Format("SELECT * FROM [{0}];", tableName);
SqlDataReader reader = (SqlDataReader)command.ExecuteReader();
while (reader.Read())
{
var student = new Student(); // You have to bind dynamic property here based on your table entities
student.FirstName = reader["FirstName"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
student.LastName = reader["LastName"].ToString();
_listStudent.Add(student);
}
reader.Close();
command.Dispose();
connection.Close();
}
有可能;我只是为了一个宠物项目而不得不这样做。
您需要引用 Microsoft.EntityFrameworkCore.Relational NuGet。
ConsoleApp 示例:
Program.cs
using System.Collections.Generic;
namespace EfDirectSql
{
class Program
{
/*
* written: VS2019 .Net Core 3.1 Console App
*
* used nugets:
*
* Microsoft.EntityFrameworkCore.SqlServer 3.1.0
* Microsoft.EntityFrameworkCore.Relational 3.1.0
*
*/
static void Main(string[] args)
{
// attention: supply your database server name
ApplicationContext context = new ApplicationContext("?YOURSERVER?", "Master");
// note: leveraging included extension methods for the dbContext class.
object scalarResult = context.ExecuteScalar("SELECT COUNT(1) FROM Master.dbo.SysObjects");
object nonQueryResult = context.ExecuteNonQuery("SELECT * FROM Master.dbo.SysObjects"); // likely your -1
IEnumerable<SysObject> readerResult = context.ExecuteReader<SysObject>("SELECT * FROM Master.dbo.SysObjects");
}
}
}
ApplicationContext.cs
using Microsoft.EntityFrameworkCore;
namespace EfDirectSql
{
public class ApplicationContext
: DbContext
{
public ApplicationContext(string serverName, string catalogName)
{
this.ServerName = serverName;
this.CatalogName = catalogName;
}
public readonly string ServerName;
public readonly string CatalogName;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer($"Data Source={this.ServerName};Initial Catalog={this.CatalogName};Integrated Security=true;");
base.OnConfiguring(optionsBuilder);
}
}
}
DbContextExtensions.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
namespace EfDirectSql
{
public static class DbContextExtensions
{
public static object ExecuteScalar
(
this DbContext context,
string sql
)
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
object result = null;
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
result = command.ExecuteScalar();
}
finally
{
connection.Close();
}
return result;
}
public static int ExecuteNonQuery
(
this DbContext context,
string sql
)
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
int result;
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
result = command.ExecuteNonQuery();
// likely the -1
}
finally
{
connection.Close();
}
return result;
}
public static IEnumerable<TType> ExecuteReader<TType>
(
this DbContext context,
string sql
)
where TType : class, new()
{
IDbConnection connection = context.Database.GetDbConnection();
IDbCommand command = connection.CreateCommand();
IEnumerable<TType> result = new List<TType>();
try
{
connection.Open();
command.CommandText = sql;
command.CommandType = CommandType.Text;
IDataReader reader = command.ExecuteReader(CommandBehavior.Default);
result = Convert<TType>(reader);
}
finally
{
connection.Close();
}
return result;
}
private static IEnumerable<TType> Convert<TType>(IDataReader reader)
where TType : class, new()
{
List<PropertyInfo> properties = typeof(TType)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite)
.ToList();
IList<TType> instances = new List<TType>();
while (reader.Read())
{
TType instance = new TType();
properties
.ForEach
(p =>
// for the purposes of the example, this works - could be outliers.
p.SetValue(instance, reader[p.Name] == DBNull.Value ? null : reader[p.Name])
);
instances.Add(instance);
}
return instances;
}
}
}
SysObject.cs
namespace EfDirectSql
{
// shortened represenation of the MS-SQL sysobject table
public class SysObject
{
public string name { get; set; }
public int id { get; set; }
public string xtype { get; set; }
public int uid { get; set; }
public int info { get; set; }
public int status { get; set; }
// the rest are not needed for a demo.
}
}