2016-02-25 83 views
19

隨着實體框架核心刪除dbData.Database.SqlQuery<SomeModel>我找不到解決方案爲我的全文搜索查詢構建原始SQL查詢,該查詢將返回表數據和等級。沒有DbSet的原始SQL查詢 - 實體框架核心

我在Entity Framework Core中構建原始SQL查詢的唯一方法是通過dbData.Product.FromSql("SQL SCRIPT");,這是沒有用的,因爲我沒有DbSet將映射查詢中返回的排名。

任何想法???

+8

我會非常想念SqlQuery ,並且不想將自定義類映射到我的DbContext,當我真的只需要一個簡單的DTO用於特定用例時。我創建了一個用戶語音來請求將此功能重新添加到EF Core,任何人都可以投票,如果他們希望返回此功能:https://data.uservoice。com/forums/72025-entity-framework-feature-suggestions/suggestions/13183638-add-dbcontext-database-sqlquery-to-entity-framewor –

+1

根據https://github.com/aspnet/EntityFramework/issues/1862,這現在的目標是EF核心1.2和/或1.1.0-preview1 –

回答

15

在EF Core中,您不再可以執行「免費」原始sql。您需要爲該類定義POCO類和DbSet。 在你的情況,你需要定義排名

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

由於這將是肯定只讀這將是有益的包括.AsNoTracking()電話。

+2

所以我想我也必須擴展'DbContext'以包含一個新屬性'DbSet Rank {get;組; }'。現在參考linq會產生什麼樣的影響? I.e.不會我們現在能夠使用'DBContext.Rank.Where(i => i.key == 1)'這樣的語句,並且這個語句不會在SQL中實現並因此失敗嗎? –

+0

Linq排出的這組數據必須在內存中解決。如果您需要發出不同的WHERE sql子句,則必須將它們包含爲參數或構建不同的腳本。 –

+0

我的DbSet沒有「FromSql」方法。這是我失蹤的擴展嗎? – birwin

8

您可以在EF Core中執行raw 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]); 
    } 
} 
2

現在,直到有新的東西從EFCore我會用一個命令 和手動映射它

using (var command = this.DbContext.Database.GetDbConnection().CreateCommand()) 
     { 
      command.CommandText = "SELECT ... WHERE ...> @p1)"; 
      command.CommandType = CommandType.Text; 
      var parameter = new SqlParameter("@p1",...); 

      this.DbContext.Database.OpenConnection(); 

      using (var result = command.ExecuteReader()) 
      { 
       while (result.Read()) 
       { 
        .... // Map to your entity 
       } 
      } 
     } 

嘗試使用SqlParameter來避免Sql注入。

 dbData.Product.FromSql("SQL SCRIPT"); 

FromSql不適用於完整查詢。例如,如果你想包含一個WHERE子句,它將被忽略。

幾個環節:

Executing Raw SQL Queries using Entity Framework Core

Raw SQL Queries

3

建立在我寫這個幫手完成任務的其他的答案,包括用法示例:

public static class Helper 
{ 
    public static List<T> RawSqlQuery<T>(string query, Func<DbDataReader, T> map) 
    { 
     using (var context = new WannaSportContext()) 
     { 
      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; 
       } 
      } 
     } 
    } 

用法:

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

我計劃一旦添加內置支持就立即擺脫它。根據EF核心團隊的Arthur Vickers的statement,這是後2.0的高優先級。該問題正在跟蹤here