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

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

有什么想法?


当前回答

查询数据:不存在实体

               string query = "SELECT r.Name as roleName, ur.roleId, u.Id as userId   FROM dbo.AspNetUserRoles AS ur INNER JOIN dbo.AspNetUsers AS u ON ur.UserId = u.Id INNER JOIN dbo.AspNetRoles AS r ON ur.RoleId = r.Id ";

               ICollection<object> usersWithRoles = new List<object>();
                using (var command = _identityDBContext.Database.GetDbConnection().CreateCommand())
                {
                    command.CommandText = query;
                    command.CommandType = CommandType.Text;

                    await _identityDBContext.Database.OpenConnectionAsync();

                    using (var reader = await command.ExecuteReaderAsync())
                    {      
                        while (await reader.ReadAsync())
                        {
                            usersWithRoles.Add(new { 
                                roleName = reader.GetFieldValueAsync<string>(0).Result, 
                                roleId = reader.GetFieldValueAsync<string>(1).Result,
                                userId = reader.GetFieldValueAsync<string>(2).Result
                            });
                        }    
                    }
                }

详细:

 [HttpGet]
    [Route("GetAllUsersWithRoles")]
    public async Task<IActionResult> GetAllUsersWithRoles()
    {
        string query = "SELECT r.Name as roleName, ur.roleId, u.Id as userId   FROM dbo.AspNetUserRoles AS ur INNER JOIN dbo.AspNetUsers AS u ON ur.UserId = u.Id INNER JOIN dbo.AspNetRoles AS r ON ur.RoleId = r.Id ";
        try
        {
            ICollection<object> usersWithRoles = new List<object>();
            using (var command = _identityDBContext.Database.GetDbConnection().CreateCommand())
            {
                command.CommandText = query;
                command.CommandType = CommandType.Text;

                await _identityDBContext.Database.OpenConnectionAsync();

                using (var reader = await command.ExecuteReaderAsync())
                {      
                    while (await reader.ReadAsync())
                    {
                        usersWithRoles.Add(new { 
                            roleName = reader.GetFieldValueAsync<string>(0).Result, 
                            roleId = reader.GetFieldValueAsync<string>(1).Result,
                            userId = reader.GetFieldValueAsync<string>(2).Result
                        });
                    }    
                }
            }
                return StatusCode(200, usersWithRoles); // Get all users   
        }
        catch (Exception e)
        {
            return StatusCode(500, e);
        }
    }

结果如下所示:

[
  {
    "roleName": "admin",
    "roleId": "7c9cb1be-e987-4ec1-ae4d-e4c9790f57d8",
    "userId": "12eadc86-6311-4d5e-8be8-df30799df265"
  },
  {
    "roleName": "user",
    "roleId": "a0d5ef46-b1e6-4a53-91ce-9ff5959f1ed8",
    "userId": "12eadc86-6311-4d5e-8be8-df30799df265"
  },
  {
    "roleName": "user",
    "roleId": "a0d5ef46-b1e6-4a53-91ce-9ff5959f1ed8",
    "userId": "3e7cd970-8c52-4dd1-847c-f824671ea15d"
  }
]

其他回答

实际上,您可以创建一个通用的存储库并做类似的事情

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : BaseEntity
{
    private readonly DataContext context;
    private readonly DbSet<TEntity> dbSet;

    public GenericRepository(DataContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

   
    public IEnumerable<TEntity> ExecuteCommandQuery(string command)
        => dbSet.FromSqlRaw(command);

}

在EF核心你不再可以执行“自由”原始sql。您需要为该类定义一个POCO类和一个DbSet。 在你的情况下,你需要定义Rank:

var ranks = DbContext.Ranks
   .FromSql("SQL_SCRIPT OR STORED_PROCEDURE @p0,@p1,...etc", parameters)
   .AsNoTracking().ToList();

因为它肯定是只读的,所以包含. asnotracking()调用会很有用。

EF Core 3.0的突破性变化:

DbQuery()现在已经过时了,取而代之的应该是DbSet()。如果你有一个无键实体,即它不需要主键,你可以使用HasNoKey()方法:

ModelBuilder.Entity<SomeModel>().HasNoKey()

更多信息可以在这里找到

你可以用这个:

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()))
        {
            // share the current database transaction, if one exists
            var transaction = db.Database.CurrentTransaction;
            if (transaction != null)
                db2.Database.UseTransaction(transaction.GetDbTransaction());
            return db2.Set<T>().FromSqlRaw(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)
        {
            optionsBuilder.UseSqlServer(connection, options => options.EnableRetryOnFailure());

            base.OnConfiguring(optionsBuilder);
        }

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

以及用法:

    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");
    }

在Core 2.1中,你可以这样做:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
       modelBuilder.Query<Ranks>();
}

然后定义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;
}

这样就不会在数据库中创建rank模型。

现在在你的控制器/动作中你可以调用:

List<Ranks> gettingRanks = _DbContext.GetRanks(value1,value2).Result.ToListAsync();

这样就可以调用原始SQL过程。

添加Nuget包- Microsoft.EntityFrameworkCore.Relational

using Microsoft.EntityFrameworkCore;
...
await YourContext.Database.ExecuteSqlCommandAsync("... @p0, @p1", param1, param2 ..)

这将以int形式返回行号

参见- https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.executesqlcommand?view=efcore-3.0