Dav*_*low 79 c# entity-framework-core
使用Entity Framework Core删除dbData.Database.SqlQuery<SomeModel>
我无法找到为我的全文搜索查询构建原始SQL查询的解决方案,该查询将返回表数据以及排名.
我见过在Entity Framework Core中构建原始SQL查询的唯一方法是通过dbData.Product.FromSql("SQL SCRIPT");
它没有用,因为我没有DbSet来映射我在查询中返回的排名.
有任何想法吗???
Cod*_*und 92
如果您使用自2018年7月7日起可用的EF Core 2.1 Release Candidate 1,则可以利用建议的新功能,即查询类型.
什么是查询类型?
除了实体类型之外,EF Core模型还可以包含查询类型,这些查询类型可用于对未映射到实体类型的数据执行数据库查询.
何时使用查询类型?
用作ad hoc FromSql()查询的返回类型.
映射到数据库视图.
映射到未定义主键的表.
映射到模型中定义的查询.
所以你不再需要做所有的黑客或解决方案作为你的问题的答案.只需按以下步骤操作:
首先,您定义了一个类型的新属性,DbQuery<T>
其中T
,该类是将携带SQL查询的列值的类的类型.所以,DbContext
你将拥有这个:
public DbQuery<SomeModel> SomeModels { get; set; }
Run Code Online (Sandbox Code Playgroud)
其次FromSql
像你一样使用方法DbSet<T>
:
var result = context.SomeModels.FromSql("SQL_SCRIPT").ToList();
var result = await context.SomeModels.FromSql("SQL_SCRIPT").ToListAsync();
Run Code Online (Sandbox Code Playgroud)
另请注意,DBContexts是部分类,因此您可以创建一个或多个单独的文件来组织最适合您的"原始SQL DbQuery"定义.
E-B*_*Bat 26
在EF Core中,您不再可以执行"免费"原始sql.您需要为该类定义POCO类和a DbSet
.在您的情况下,您将需要定义Rank:
var ranks = DbContext.Ranks
.FromSql("SQL_SCRIPT OR STORED_PROCEDURE @p0,@p1,...etc", parameters)
.AsNoTracking().ToList();
Run Code Online (Sandbox Code Playgroud)
因为它肯定是只读的,所以包含这个.AsNoTracking()
电话会很有用.
piu*_*ius 24
在其他答案的基础上,我编写了这个帮助程序来完成任务,包括示例用法:
public static class Helper
{
public static List<T> RawSqlQuery<T>(string query, Func<DbDataReader, T> map)
{
using (var context = new DbContext())
{
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = query;
command.CommandType = CommandType.Text;
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
var entities = new List<T>();
while (result.Read())
{
entities.Add(map(result));
}
return entities;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
public class TopUser
{
public string Name { get; set; }
public int Count { get; set; }
}
var result = Helper.RawSqlQuery(
"SELECT TOP 10 Name, COUNT(*) FROM Users U"
+ " INNER JOIN Signups S ON U.UserId = S.UserId"
+ " GROUP BY U.Name ORDER BY COUNT(*) DESC",
x => new TopUser { Name = (string)x[0], Count = (int)x[1] });
result.ForEach(x => Console.WriteLine($"{x.Name,-25}{x.Count}"));
Run Code Online (Sandbox Code Playgroud)
我计划在添加内置支持后立即将其删除.根据EF Core团队的Arthur Vickers的一份声明,它是2.0后的重中之重.这个问题正在跟踪这里.
Yeh*_*erg 19
您可以在EF Core中执行原始sql - 将此类添加到您的项目中.这将允许您执行原始SQL并获得原始结果,而无需定义POCO和DBSet.有关原始示例,请参阅https://github.com/aspnet/EntityFramework/issues/1862#issuecomment-220787464.
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.EntityFrameworkCore
{
public static class RDFacadeExtensions
{
public static RelationalDataReader ExecuteSqlQuery(this DatabaseFacade databaseFacade, string sql, params object[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteReader(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues);
}
}
public static async Task<RelationalDataReader> ExecuteSqlQueryAsync(this DatabaseFacade databaseFacade,
string sql,
CancellationToken cancellationToken = default(CancellationToken),
params object[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return await rawSqlCommand
.RelationalCommand
.ExecuteReaderAsync(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues,
cancellationToken: cancellationToken);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它的示例:
// Execute a query.
using(var dr = await db.Database.ExecuteSqlQueryAsync("SELECT ID, Credits, LoginDate FROM SamplePlayer WHERE " +
"Name IN ('Electro', 'Nitro')"))
{
// Output rows.
var reader = dr.DbDataReader;
while (reader.Read())
{
Console.Write("{0}\t{1}\t{2} \n", reader[0], reader[1], reader[2]);
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*kEJ 11
您可以使用它(来自https://github.com/aspnet/EntityFrameworkCore/issues/1862#issuecomment-451671168):
public static class SqlQueryExtensions
{
public static IList<T> SqlQuery<T>(this DbContext db, string sql, params object[] parameters) where T : class
{
using (var db2 = new ContextForQueryType<T>(db.Database.GetDbConnection()))
{
return db2.Query<T>().FromSql(sql, parameters).ToList();
}
}
private class ContextForQueryType<T> : DbContext where T : class
{
private readonly DbConnection connection;
public ContextForQueryType(DbConnection connection)
{
this.connection = connection;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// switch on the connection type name to enable support multiple providers
// var name = con.GetType().Name;
optionsBuilder.UseSqlServer(connection, options => options.EnableRetryOnFailure());
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<T>().HasNoKey();
base.OnModelCreating(modelBuilder);
}
}
}
Run Code Online (Sandbox Code Playgroud)
以及用法:
using (var db = new Db())
{
var results = db.SqlQuery<ArbitraryType>("select 1 id, 'joe' name");
//or with an anonymous type like this
var results2 = db.SqlQuery(() => new { id =1, name=""},"select 1 id, 'joe' name");
}
Run Code Online (Sandbox Code Playgroud)
现在,在EFCore有了新功能之前,我将使用命令并手动将其映射
using (var command = this.DbContext.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "SELECT ... WHERE ...> @p1)";
command.CommandType = CommandType.Text;
var parameter = new SqlParameter("@p1",...);
command.Parameters.Add(parameter);
this.DbContext.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
while (result.Read())
{
.... // Map to your entity
}
}
}
Run Code Online (Sandbox Code Playgroud)
尝试使用SqlParameter避免Sql注入。
dbData.Product.FromSql("SQL SCRIPT");
Run Code Online (Sandbox Code Playgroud)
FromSql不适用于完整查询。例如,如果您想包含WHERE子句,它将被忽略。
一些链接:
使用Entity Framework Core执行原始SQL查询
试试这个:(创建扩展方法)
public static List<T> ExecuteQuery<T>(this dbContext db, string query) where T : class, new()
{
using (var command = db.Database.GetDbConnection().CreateCommand())
{
command.CommandText = query;
command.CommandType = CommandType.Text;
db.Database.OpenConnection();
using (var reader = command.ExecuteReader())
{
var lst = new List<T>();
var lstColumns = new T().GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
while (reader.Read())
{
var newObject = new T();
for (var i = 0; i < reader.FieldCount; i++)
{
var name = reader.GetName(i);
PropertyInfo prop = lstColumns.FirstOrDefault(a => a.Name.ToLower().Equals(name.ToLower()));
if (prop == null)
{
continue;
}
var val = reader.IsDBNull(i) ? null : reader[i];
prop.SetValue(newObject, val, null);
}
lst.Add(newObject);
}
return lst;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
var db = new dbContext();
string query = @"select ID , Name from People where ... ";
var lst = db.ExecuteQuery<PeopleView>(query);
Run Code Online (Sandbox Code Playgroud)
我的模型:(不在DbSet
):
public class PeopleView
{
public int ID { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
中测试
.netCore 2.2 and 3.0
。
注意:此解决方案性能较慢
在Core 2.1中,您可以执行以下操作:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Query<Ranks>();
}
Run Code Online (Sandbox Code Playgroud)
然后定义您的SQL过程,例如:
public async Task<List<Ranks>> GetRanks(string value1, Nullable<decimal> value2)
{
SqlParameter value1Input = new SqlParameter("@Param1", value1?? (object)DBNull.Value);
SqlParameter value2Input = new SqlParameter("@Param2", value2?? (object)DBNull.Value);
List<Ranks> getRanks = await this.Query<Ranks>().FromSql("STORED_PROCEDURE @Param1, @Param2", value1Input, value2Input).ToListAsync();
return getRanks;
}
Run Code Online (Sandbox Code Playgroud)
这样,将不会在数据库中创建Ranks模型。
现在,在您的控制器/操作中,您可以调用:
List<Ranks> gettingRanks = _DbContext.GetRanks(value1,value2).Result.ToListAsync();
Run Code Online (Sandbox Code Playgroud)
这样,您可以调用Raw SQL Procedures。
添加 Nuget 包 - Microsoft.EntityFrameworkCore.Relational
using Microsoft.EntityFrameworkCore;
...
await YourContext.Database.ExecuteSqlCommandAsync("... @p0, @p1", param1, param2 ..)
Run Code Online (Sandbox Code Playgroud)
这会将行号作为 int 返回
小智 6
我在github上找到了EntityFrameworkCore.RawSQLExtensions包。要使用它,请添加 nuget 包。
<PackageReference Include="EntityFrameworkCore.RawSQLExtensions" Version="1.2.0" />
Run Code Online (Sandbox Code Playgroud)
该库没有记录,但下面是我在 .NET 6 + EF Core 6 + Npgsql 6 中使用它的情况
public class DbResult
{
public string Name { get; set; }
public int Age { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
using EntityFrameworkCore.RawSQLExtensions.Extensions;
Run Code Online (Sandbox Code Playgroud)
var results = await context.Database
.SqlQuery<DbResult>(
@"select name, age from ""users"" where age > @Age",
new NpgsqlParameter("@Age", 15))
.ToListAsync();
Run Code Online (Sandbox Code Playgroud)
我使用Dapper来绕过 Entity Framework Core 的这个限制。
IDbConnection.Query
Run Code Online (Sandbox Code Playgroud)
正在使用具有多个参数的 SQL 查询或存储过程。顺便说一句,它更快一点(请参阅基准测试)
Dapper 很容易学习。编写并运行带参数的存储过程花了 15 分钟。无论如何,您可以同时使用 EF 和 Dapper。下面是一个例子:
public class PodborsByParametersService
{
string _connectionString = null;
public PodborsByParametersService(string connStr)
{
this._connectionString = connStr;
}
public IList<TyreSearchResult> GetTyres(TyresPodborView pb,bool isPartner,string partnerId ,int pointId)
{
string sqltext "spGetTyresPartnerToClient";
var p = new DynamicParameters();
p.Add("@PartnerID", partnerId);
p.Add("@PartnerPointID", pointId);
using (IDbConnection db = new SqlConnection(_connectionString))
{
return db.Query<TyreSearchResult>(sqltext, p,null,true,null,CommandType.StoredProcedure).ToList();
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
62565 次 |
最近记录: |