与实体框架核心删除dbData.Database。我找不到一个解决方案来构建一个原始的SQL查询为我的全文搜索查询,将返回表数据和排名。

我所见过的在实体框架核心中构建原始SQL查询的唯一方法是通过dbData.Product。FromSql(“SQL脚本”);这是没有用的,因为我没有DbSet,将映射我在查询中返回的排名。

有什么想法?


当前回答

在实体框架6中,你可以执行如下内容

创建模态类为

Public class User
{
        public int Id { get; set; }
        public string fname { get; set; }
        public string lname { get; set; }
        public string username { get; set; }
}

执行Raw DQL SQl命令如下所示:

var userList = datacontext.Database.SqlQuery<User>(@"SELECT u.Id ,fname , lname ,username FROM dbo.Users").ToList<User>();

其他回答

我更新了扩展方法从@AminRostami返回IAsyncEnumerable(这样LINQ过滤可以应用),它的映射模型列名的记录从DB返回到模型(EF Core 5测试):

扩展本身:

public static class QueryHelper
{
    private static string GetColumnName(this MemberInfo info)
    {
        List<ColumnAttribute> list = info.GetCustomAttributes<ColumnAttribute>().ToList();
        return list.Count > 0 ? list.Single().Name : info.Name;
    }
    /// <summary>
    /// Executes raw query with parameters and maps returned values to column property names of Model provided.
    /// Not all properties are required to be present in model (if not present - null)
    /// </summary>
    public static async IAsyncEnumerable<T> ExecuteQuery<T>(
        [NotNull] this DbContext db,
        [NotNull] string query,
        [NotNull] params SqlParameter[] parameters)
        where T : class, new()
    {
        await using DbCommand command = db.Database.GetDbConnection().CreateCommand();
        command.CommandText = query;
        command.CommandType = CommandType.Text;
        if (parameters != null)
        {
            foreach (SqlParameter parameter in parameters)
            {
                command.Parameters.Add(parameter);
            }
        }
        await db.Database.OpenConnectionAsync();
        await using DbDataReader reader = await command.ExecuteReaderAsync();
        List<PropertyInfo> lstColumns = new T().GetType()
            .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
        while (await reader.ReadAsync())
        {
            T newObject = new();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                string name = reader.GetName(i);
                PropertyInfo prop = lstColumns.FirstOrDefault(a => a.GetColumnName().Equals(name));
                if (prop == null)
                {
                    continue;
                }
                object val = await reader.IsDBNullAsync(i) ? null : reader[i];
                prop.SetValue(newObject, val, null);
            }
            yield return newObject;
        }
    }
}

使用的模型(注意列名与实际的属性名不同):

public class School
{
    [Key] [Column("SCHOOL_ID")] public int SchoolId { get; set; }

    [Column("CLOSE_DATE", TypeName = "datetime")]
    public DateTime? CloseDate { get; set; }

    [Column("SCHOOL_ACTIVE")] public bool? SchoolActive { get; set; }
}

实际的用法:

public async Task<School> ActivateSchool(int schoolId)
{
    // note that we're intentionally not returning "SCHOOL_ACTIVE" with select statement
    // this might be because of certain IF condition where we return some other data
    return await _context.ExecuteQuery<School>(
        "UPDATE SCHOOL SET SCHOOL_ACTIVE = 1 WHERE SCHOOL_ID = @SchoolId; SELECT SCHOOL_ID, CLOSE_DATE FROM SCHOOL",
        new SqlParameter("@SchoolId", schoolId)
    ).SingleAsync();
}

我使用Dapper绕过了Entity框架Core的这个约束。

IDbConnection.Query

正在处理带有多个参数的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();
        }


        }
}

在实体框架6中,你可以执行如下内容

创建模态类为

Public class User
{
        public int Id { get; set; }
        public string fname { get; set; }
        public string lname { get; set; }
        public string username { get; set; }
}

执行Raw DQL SQl命令如下所示:

var userList = datacontext.Database.SqlQuery<User>(@"SELECT u.Id ,fname , lname ,username FROM dbo.Users").ToList<User>();

如果您使用EF Core 3.0或更新版本

你需要使用无键实体类型,以前称为查询类型:

该特性是在EF Core 2.1中以查询类型的名称添加的。 在EF Core 3.0中,这个概念被重命名为无键实体类型。的 [无键]数据注释在EFCore 5.0中可用。

要使用它们,你需要首先用[Keyless]数据注释标记你的类SomeModel,或者通过.HasNoKey()方法调用进行流畅配置,如下所示:

public DbSet<SomeModel> SomeModels { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<SomeModel>().HasNoKey();
}

配置完成后,可以使用这里解释的方法之一来执行SQL查询。例如,你可以用这个:

var result = context.SomeModels.FromSqlRaw("SQL SCRIPT").ToList();
var result = await context.SomeModels.FromSql("SQL_SCRIPT").ToListAsync();

如果您正在使用EF Core 2.1

如果您正在使用2018年5月7日发布的EF Core 2.1候选版本1,您可以利用提议的新功能,即查询类型:

除了实体类型,EF Core模型还可以包含查询类型, 哪些可以用于对数据进行数据库查询 没有映射到实体类型。

什么时候使用查询类型?

作为临时FromSql()查询的返回类型。 映射到数据库视图。 映射到没有定义主键的表。 映射到模型中定义的查询。

所以你不再需要做所有的黑客或变通方法来回答你的问题。只需遵循以下步骤:

首先,您定义了一个DbQuery<T>类型的新属性,其中T是将携带SQL查询列值的类的类型。在你的DbContext中,你会有这个:

public DbQuery<SomeModel> SomeModels { get; set; }

其次,使用FromSql方法,就像使用DbSet<T>一样:

var result = context.SomeModels.FromSql("SQL_SCRIPT").ToList();
var result = await context.SomeModels.FromSql("SQL_SCRIPT").ToListAsync();

还要注意dbcontext是部分类,所以你可以创建一个或多个单独的文件来组织最适合你的“原始SQL DbQuery”定义。

你可以在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);
            }
        }
    }
}

下面是一个如何使用它的例子:

// 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]);
    }
}