2016-02-25 7 views
19

Mit Entity Framework Core entfernen dbData.Database.SqlQuery<SomeModel> Ich kann keine Lösung finden, um eine Raw SQL-Abfrage für meine Volltext-Suchabfrage zu erstellen, die die Tabellendaten und auch den Rang zurückgibt.Raw SQL Query ohne DbSet - Entity Framework Core

Die einzige Methode, die ich gesehen habe, um eine raw SQL-Abfrage in Entity Framework Core zu erstellen, ist über dbData.Product.FromSql("SQL SCRIPT");, die nicht nützlich ist, da ich kein DbSet haben, die den Rang I in der Abfrage zurückgeben.

Irgendwelche Ideen ???

+8

Ich werde die SqlQuery sehr vermissen und möchte keine benutzerdefinierten Klassen zu meinem DbContext zuordnen, wenn ich wirklich nur ein einfaches DTO für einen bestimmten Anwendungsfall brauche. Ich habe eine Benutzerstimme erstellt, um das Hinzufügen dieser Funktion in EF Core anzufordern, die jeder wählen kann, wenn er diese Funktion zurück möchte: https: //data.uservoice.com/forums/72025-Entity-Framework-Feature-Vorschläge/Vorschläge/13183638-Add-dbcontext-Datenbank-sqlquery-to-entity-framewor –

+1

Nach https://github.com/aspnet/EntityFramework/issues/1862, Dies ist jetzt Ziel für EF Core 1.2 und/oder 1.1.0-preview1 –

Antwort

15

In EF Core können Sie nicht mehr "freie" rohe SQL ausführen. Sie müssen eine POCO-Klasse und eine DbSet für diese Klasse definieren. In Ihrem Fall müssen Sie Rang definieren:

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

Wie es sicherlich nur lesbar sein wird, wird es hilfreich sein, den .AsNoTracking() Anruf aufzunehmen.

+2

Also ich denke, ich muss auch den 'DbContext' erweitern, um eine neue Eigenschaft' DbSet Rank {get; einstellen; } '. Was bedeutet das für linq? I.e. Können wir jetzt nicht eine Anweisung wie 'DBContext.Rank.Where (i => i.key == 1)' verwenden, und wird diese Anweisung keine Implementierung in SQL haben und daher fehlschlagen? –

+0

Linq emittiert gegen diesen Satz muss im Speicher aufgelöst werden. Wenn Sie eine andere WHERE-Klausel ausgeben müssen, müssen Sie sie als Parameter angeben oder ein anderes Skript erstellen. –

+0

Mein DbSet hat keine "FromSql" -Methode. Ist das eine Erweiterung, die ich vermisse? – birwin

8

Sie können Raw SQL in EF Core ausführen - Fügen Sie diese Klasse zu Ihrem Projekt hinzu. Dadurch können Sie Raw SQL ausführen und die rohen Ergebnisse erhalten, ohne ein POCO und ein DBSet zu definieren. Siehe Original-Beispiel 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); 
      } 
     } 
    } 
} 

Hier ist ein Beispiel dafür, wie es zu benutzen:

// 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

Vorerst bis es etwas Neues von EFCore ist, würde ich einen Befehl verwendet und wo es sich

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 
       } 
      } 
     } 

manuell Versuchen Sie SqlParameter, Sql-Injektion zu vermeiden.

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

FromSql funktioniert nicht mit vollständiger Abfrage. Beispiel wenn Sie eine WHERE-Klausel einfügen wollen, wird diese ignoriert.

Einige Links:

Executing Raw SQL Queries using Entity Framework Core

Raw SQL Queries

3

Aufbauend auf den anderen Antworten, die ich diese Helfer geschrieben habe, dass die Aufgabe, einschließlich Beispiel für die Verwendung erfüllt:

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

Verbrauch:

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

Ich plane, es loszuwerden, sobald die eingebaute Unterstützung hinzugefügt wird. Laut einer statement von Arthur Vickers vom EF Core-Team hat dies eine hohe Priorität für Post 2.0. Das Problem wird verfolgt here.

Verwandte Themen