DbSet olmadan Ham SQL Sorgusu - Entity Framework Core


120

Entity Framework Core kaldırıldığında dbData.Database.SqlQuery<SomeModel>, tablo verilerini ve ayrıca sıralamayı döndürecek tam metin arama sorgum için ham bir SQL Sorgusu oluşturmak için bir çözüm bulamıyorum.

Entity Framework Core'da ham bir SQL sorgusu oluşturmak için gördüğüm tek yöntem dbData.Product.FromSql("SQL SCRIPT");, sorguda döndürdüğüm sıralamayı eşleyecek DbSet'e sahip olmadığım için yararlı olmayan yöntemdir.

Herhangi bir fikir???


15
SqlQuery <T> 'yi çok özleyeceğim ve belirli bir kullanım durumu için gerçekten sadece basit bir DTO'ya ihtiyacım olduğunda özel sınıfları DbContext'imle eşlemek zorunda kalmak istemiyorum. Bu özelliği tekrar EF Core'a eklemek isteyen herkesin bu özelliği geri isterse oy verebileceği bir kullanıcı sesi oluşturdum: data.uservoice.com/forums/…
Matt Sanders

1
Github.com/aspnet/EntityFramework/issues/1862'ye göre , bu artık EF core 1.2 ve / veya 1.1.0-preview1 için hedefleniyor
Dan Field

2
@ Devon'un az önce söylediklerine dayanarak, bunların Microsoft.EntityFrameworkCore.SqlServer'da uzantı yöntemleri olduğunu anlamak için çok uzun zaman harcadım. Bu uzatma yöntemlerini almadan önce bunu projenize eklemeniz gerekecek.
Daniel

3
Sigh Bu Mimarlık Astronot kararının bir tür gibi görünüyor: "İnsanlar bunu istiyor gerekmez". Sanırım sadece bu durum için Dapper'ı kurmam gerekiyor. Can sıkıcı.
Dirk Boer

1
@MattSanders - kullanıyorsunuzSes bağlantısı bu arada bitmiş gibi görünüyor. Nereye gittiğini biliyor musun?
Dirk Boer

Yanıtlar:


139

EF Core 2.1 veya EF Core 3 ve daha yüksek sürümleri kullanıp kullanmadığınıza bağlıdır .

EF Core 2.1 kullanıyorsanız

7 Mayıs 2018'den beri sunulan EF Core 2.1 Release Candidate 1'i kullanıyorsanız, Query type olan önerilen yeni özellikten yararlanabilirsiniz.

Nedir sorgu türü ?

Varlık türlerine ek olarak, bir EF Core modeli, varlık türlerine eşlenmemiş verilere karşı veritabanı sorguları gerçekleştirmek için kullanılabilen sorgu türleri içerebilir.

Sorgu türü ne zaman kullanılır?

Ad hoc FromSql () sorguları için dönüş türü olarak hizmet veriyor.

Veritabanı görünümlerine eşleme.

Birincil anahtarı tanımlanmamış tablolarla eşleme.

Modelde tanımlanan sorgulara eşleme.

Böylece, sorunuza yanıt olarak önerilen tüm hack'leri veya geçici çözümleri artık yapmanız gerekmiyor. Şu adımları uygulamanız yeterlidir:

Öncelikle , SQL sorgunuzun sütun değerlerini taşıyacak sınıfın türünün DbQuery<T>bulunduğu yeni bir tür özelliği tanımladınız T. Yani senin içinde buna DbContextsahip olacaksın:

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

İkinci olarak, FromSqlyaptığınız gibi yöntemi kullanın DbSet<T>:

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

Ayrıca unutmayın DdContextler vardır kısmi sınıfları size en iyi takım elbise gibi 'ham SQL dbquery' tanımlarını düzenlemek için bir veya daha fazla ayrı dosya oluşturabilir, böylece.


EF Core 3.0 ve daha yüksek sürümleri kullanıyorsanız

Sorgu türü artık Anahtarsız varlık türü olarak biliniyor . Yukarıda belirtildiği gibi, sorgu türleri EF Core 2.1'de tanıtıldı. EF Core 3.0 veya daha yüksek bir sürümü kullanıyorsanız, artık anahtarsız tntity türlerini kullanmayı düşünmelisiniz çünkü sorgu türleri artık eski olarak işaretlenmiştir.

Bu özellik, sorgu türleri adı altında EF Core 2.1'de eklenmiştir. EF Core 3.0'da kavram, anahtarsız varlık türleri olarak yeniden adlandırıldı. [Anahtarsız] Veri Ek Açıklaması EFCore 5.0'da kullanıma sunuldu.

Anahtarsız varlık türünün ne zaman kullanılacağına ilişkin sorgu türleriyle aynı senaryolara sahibiz.

Yani öncelikle sınıf işaretlemek gerekir kullanmak SomeModelile [Keyless]veri açıklama ya da akıcı yapılandırma yoluyla .HasNoKey()aşağıda gibi yöntem çağrısı:

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

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

Bu yapılandırmadan sonra, SQL sorgunuzu yürütmek için burada açıklanan yöntemlerden birini kullanabilirsiniz . Örneğin bunu kullanabilirsiniz:

var result = context.SomeModels.FromSqlRaw("SQL SCRIPT").ToList();

18
Bu yanıt, EF Core 2.1 ve üstünü kullanırken en iyi çözüm olmalıdır. 👍
Will Huang

3
@CodeNotFound Ya sonuca ihtiyacım yoksa veya ilkel bir türse (örneğin bit)?
Shimmy Weitzhandler

6
CodeFirst kullanarak bu otomatik olarak tüm bu özelliklere sahip bir tablo oluşturdu [NotMapped], SomeModelssınıfa eklemek benim için çalışmıyor. Bir şey mi kaçırdım?
Jean-Paul

7
EF Çekirdek 3.0 karşı çıkan DbQuerysadece kullanılarak lehine DbSetolan anahtarsız varlık türleri .
NetMage

6
Bilginize, EF core 3.0'daki bazı hatalar nedeniyle, ilk kod geçişi HasNoKey () ile işaretlenmiş varlıklarda bile bir tablo oluşturmaya çalışacaktır. Yani .ToView (null) eklemeniz gerekiyor. Örneğin modelBuilder.Entity<MyData>().HasNoKey().ToView(null);@ Jean-Paul Sanırım bu sorununuzu çözer
stann1

41

Örnek kullanım da dahil olmak üzere görevi yerine getiren bu yardımcıyı diğer yanıtlara dayanarak yazdım:

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

Kullanım:

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

Yerleşik destek eklenir eklenmez ondan kurtulmayı planlıyorum. EF Core ekibinden Arthur Vickers tarafından yapılan açıklamaya göre, 2.0 sonrası için yüksek bir önceliktir. Sorun burada izleniyor .


güzel cevap, beğendim.
sebu

31

EF Core'da artık "ücretsiz" ham sql yürütemezsiniz. Bu sınıf DbSetiçin bir POCO sınıfı ve a tanımlamanız gerekir . Sizin durumunuzda, Sıralamayı tanımlamanız gerekecek :

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

Kesinlikle salt okunur olacağı için .AsNoTracking()aramayı dahil etmek faydalı olacaktır .

DÜZENLEME - EF Core 3.0'da son değişiklik:

DbQuery () artık kullanılmıyor, bunun yerine DbSet () kullanılmalı (tekrar). Anahtarsız bir varlığınız varsa, yani birincil anahtar gerektirmiyorsa, HasNoKey () yöntemini kullanabilirsiniz:

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

Daha fazla bilgiyi burada bulabilirsiniz


3
Yani sanırım DbContextyeni bir mülk dahil etmek için genişletmem gerekecek DbSet<Rank> Rank { get; set; }. Bunun linq ile ilgili olarak şimdi ne gibi etkileri olacak? Yani, artık böyle bir ifade kullanamayacağız DBContext.Rank.Where(i => i.key == 1)ve bu ifadenin SQL'de uygulaması olmayacak ve bu nedenle başarısız olmayacak mı?
David Harlow

Bu sete karşı yayılan Linq bellekte çözülmelidir. Farklı WHERE sql cümlesini yayınlamanız gerekiyorsa, bunları parametre olarak eklemeniz veya farklı bir komut dosyası oluşturmanız gerekir.
E-Bat

DbSet'imde "FromSql" yöntemi yok. Bu eksik olduğum bir uzantı mı?
birwin

1
@birwin, namespace Microsoft.EntityFrameworkCore ithalat gerekir
e-Bat

21

EF Core'da ham sql yürütebilirsiniz - Bu sınıfı projenize ekleyin. Bu, bir POCO ve bir DBSet tanımlamanıza gerek kalmadan ham SQL yürütmenize ve ham sonuçları almanıza olanak tanır. Orijinal örnek için https://github.com/aspnet/EntityFramework/issues/1862#issuecomment-220787464 adresine bakın .

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

İşte nasıl kullanılacağına dair bir örnek:

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

19

Şimdilik, EFCore'dan yeni bir şey gelene kadar bir komut kullanıp manuel olarak eşlerdim

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

Sql Injection'dan kaçınmak için SqlParameter'ı deneyin.

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

FromSql tam sorgu ile çalışmaz. Örnek, bir WHERE yan tümcesi eklemek istiyorsanız, yok sayılacaktır.

Bazı Bağlantılar:

Entity Framework Core Kullanarak Ham SQL Sorguları Yürütme

Ham SQL Sorguları


8

Bunu kullanabilirsiniz ( https://github.com/aspnet/EntityFrameworkCore/issues/1862#issuecomment-451671168 adresinden ):

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

Ve kullanım:

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

modelBulider.Query<T>()EntityFramework Core 3
zafar,

EF Core 3+ için güncellendi
ErikEJ

7

Çekirdek 2.1'de şöyle bir şey yapabilirsiniz:

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

ve sonra size SQL Prosedürünü tanımlayın, örneğin:

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

Bu şekilde, DB'nizde Ranks modeli oluşturulmayacaktır.

Şimdi denetleyicinizde / eyleminizde şunları arayabilirsiniz:

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

Bu şekilde Ham SQL Prosedürlerini çağırabilirsiniz.


FromSqlParametreler sadece yaratmadan geçirilebilecek SqlParameter: nesneyi FromSql($"STORED_PROCEDURE {value1}, {value2}")veya FromSql("STORED_PROCEDURE {0}, {1}", value1, value2)(kaçtılar edilecektir).
Majid

7

Nuget paketi ekle - Microsoft.EntityFrameworkCore.Relational

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

Bu satır numaralarını int olarak döndürecektir

Bkz - https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.executesqlcommand?view=efcore-3.0


3
Lütfen bunun yalnızca komuttan etkilenen satır sayısını döndüreceğini unutmayın: stackoverflow.com/a/49861799/299756
kalyfe

Tam olarak ihtiyacım olan şey. Microsoft.EntityFrameworkCore 3.1.1 kullanıyorum ve RAW sorgusunu ve SP'yi yürütmenin bir yolu yok. Bunun için çok teşekkür ederim!
jaysonragasa

5

şunu deneyin: (uzantı yöntemi oluştur)

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

Kullanım:

var db = new dbContext();
string query = @"select ID , Name from People where ... ";
var lst = db.ExecuteQuery<PeopleView>(query);

modelim: (içinde değil DbSet):

public class PeopleView
{
    public int ID { get; set; }
    public string Name { get; set; }
}

içinde test edildi .netCore 2.2 and 3.0.

Not: Bu çözümün performansı yavaş


Yalnızca bir ilk kayıt için PropertyInfo'da yalnızca bir kez ada göre arama yapmayı deneyin ve sonraki kayıtlarda kullanmak için sütun dizinlerine göre PropertyInfo [] dizisi oluşturun.
Petr Voborník

@AminRostami Nice Work
sebu

2

Doğrudan OP'nin senaryosunu hedef almıyorum, ancak bununla mücadele ettiğim için, bu eski sevgilileri bırakmak istiyorum. ham SQL'in şu şekilde çalıştırılmasını kolaylaştıran yöntemler DbContext:

public static class DbContextCommandExtensions
{
  public static async Task<int> ExecuteNonQueryAsync(this DbContext context, string rawSql,
    params object[] parameters)
  {
    var conn = context.Database.GetDbConnection();
    using (var command = conn.CreateCommand())
    {
      command.CommandText = rawSql;
      if (parameters != null)
        foreach (var p in parameters)
          command.Parameters.Add(p);
      await conn.OpenAsync();
      return await command.ExecuteNonQueryAsync();
    }
  }

  public static async Task<T> ExecuteScalarAsync<T>(this DbContext context, string rawSql,
    params object[] parameters)
  {
    var conn = context.Database.GetDbConnection();
    using (var command = conn.CreateCommand())
    {
      command.CommandText = rawSql;
      if (parameters != null)
        foreach (var p in parameters)
          command.Parameters.Add(p);
      await conn.OpenAsync();
      return (T)await command.ExecuteScalarAsync();
    }
  }
}

1

Entity framework Core'un bu kısıtlamasını atlamak için Dapper kullandım .

IDbConnection.Query

ya sql sorgusu ya da birden çok parametreye sahip saklı yordam ile çalışıyor. Bu arada, biraz daha hızlı ( karşılaştırma testlerine bakın )

Dapper'ın öğrenmesi kolaydır. Depolanan yordamı parametrelerle yazmak ve çalıştırmak 15 dakika sürdü. Neyse, hem EF hem de Dapper'ı kullanabilirsiniz. Aşağıda bir örnek verilmiştir:

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


        }
}

0

QueryFirst'i de kullanabilirsiniz . Dapper gibi, bu tamamen EF'in dışındadır. Dapper (veya EF) 'den farklı olarak, POCO'yu korumanıza gerek yoktur, sql SQL'inizi gerçek bir ortamda düzenlersiniz ve sürekli olarak DB'ye göre yeniden doğrulanır. Sorumluluk reddi: QueryFirst'ün yazarıyım.


0

Durumum ham SQL yerine saklı yordamı kullandı

Bir sınıf oluşturdu

Public class School
{
    [Key]
    public Guid SchoolId { get; set; }
    public string Name { get; set; }
    public string Branch { get; set; }
    public int NumberOfStudents  { get; set; }
}

Benim aşağıda eklendi DbContextsınıfa

public DbSet<School> SP_Schools { get; set; }

Depolanan yordamı yürütmek için:

var MySchools = _db.SP_Schools.FromSqlRaw("GetSchools @schoolId, @page, @size ",
              new SqlParameter("schoolId", schoolId),
              new SqlParameter("page", page),
              new SqlParameter("size", size)))
.IgnoreQueryFilters();


0

Bu çözüm, büyük ölçüde @pius'un çözümüne dayanıyor. SQL enjeksiyonunu azaltmaya yardımcı olmak için sorgu parametrelerini destekleme seçeneğini eklemek istedim ve onu biraz daha entegre hale getirmek için Entity Framework Core için DbContext DatabaseFacade dışında bir uzantı yapmak istedim.

Önce şu uzantıyla yeni bir sınıf oluşturun:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;

namespace EF.Extend
{

    public static class ExecuteSqlExt
    {
        /// <summary>
        /// Execute raw SQL query with query parameters
        /// </summary>
        /// <typeparam name="T">the return type</typeparam>
        /// <param name="db">the database context database, usually _context.Database</param>
        /// <param name="query">the query string</param>
        /// <param name="map">the map to map the result to the object of type T</param>
        /// <param name="queryParameters">the collection of query parameters, if any</param>
        /// <returns></returns>
        public static List<T> ExecuteSqlRawExt<T, P>(this DatabaseFacade db, string query, Func<DbDataReader, T> map, IEnumerable<P> queryParameters = null)
        {
            using (var command = db.GetDbConnection().CreateCommand())
            {
                if((queryParameters?.Any() ?? false))
                    command.Parameters.AddRange(queryParameters.ToArray());

                command.CommandText = query;
                command.CommandType = CommandType.Text;

                db.OpenConnection();

                using (var result = command.ExecuteReader())
                {
                    var entities = new List<T>();

                    while (result.Read())
                    {
                        entities.Add(map(result));
                    }

                    return entities;
                }
            }
                
        }
    }

}

Yukarıda "T" nin dönüş türü ve "P" nin MySql, Sql, vb. Kullanmanıza bağlı olarak değişecek olan sorgu parametrelerinizin türü olduğunu unutmayın.

Sonra bir örnek göstereceğiz. MySql EF Core özelliğini kullanıyorum, bu nedenle yukarıdaki genel uzantıyı bu daha spesifik MySql uygulamasıyla nasıl kullanabileceğimizi göreceğiz:

//add your using statement for the extension at the top of your Controller
//with all your other using statements
using EF.Extend;

//then your your Controller looks something like this
namespace Car.Api.Controllers
{

    //Define a quick Car class for the custom return type
    //you would want to put this in it's own class file probably
    public class Car
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public string DisplayTitle { get; set; }
    }

    [ApiController]
    public class CarController : ControllerBase
    {
        private readonly ILogger<CarController> _logger;
        //this would be your Entity Framework Core context
        private readonly CarContext _context;

        public CarController(ILogger<CarController> logger, CarContext context)
        {
            _logger = logger;
            _context = context;
        }

        //... more stuff here ...

       /// <summary>
       /// Get car example
       /// </summary>
       [HttpGet]
       public IEnumerable<Car> Get()
       {
           //instantiate three query parameters to pass with the query
           //note the MySqlParameter type is because I'm using MySql
           MySqlParameter p1 = new MySqlParameter
           {
               ParameterName = "id1",
               Value = "25"
           };

           MySqlParameter p2 = new MySqlParameter
           {
               ParameterName = "id2",
               Value = "26"
           };

           MySqlParameter p3 = new MySqlParameter
           {
               ParameterName = "id3",
               Value = "27"
           };

           //add the 3 query parameters to an IEnumerable compatible list object
           List<MySqlParameter> queryParameters = new List<MySqlParameter>() { p1, p2, p3 };

           //note the extension is now easily accessed off the _context.Database object
           //also note for ExecuteSqlRawExt<Car, MySqlParameter>
           //Car is my return type "T"
           //MySqlParameter is the specific DbParameter type MySqlParameter type "P"
           List<Car> result = _context.Database.ExecuteSqlRawExt<Car, MySqlParameter>(
        "SELECT Car.Make, Car.Model, CONCAT_WS('', Car.Make, ' ', Car.Model) As DisplayTitle FROM Car WHERE Car.Id IN(@id1, @id2, @id3)",
        x => new Car { Make = (string)x[0], Model = (string)x[1], DisplayTitle = (string)x[2] }, 
        queryParameters);

           return result;
       }
    }
}

Sorgu,
"Ford", "Explorer", "Ford Explorer"
"Tesla", "Model X", "Tesla Model X" gibi satırlar döndürür

Görüntü başlığı bir veritabanı sütunu olarak tanımlanmaz, bu nedenle varsayılan olarak EF Araba modelinin bir parçası olmaz. Bu yaklaşımı birçok olası çözümden biri olarak seviyorum. Bu sayfadaki diğer yanıtlar, kullanım durumunuza bağlı olarak daha uygun bir yaklaşım olabilecek [Eşlenmemiş] dekoratörle bu sorunu ele almanın diğer yollarına atıfta bulunmaktadır.

Bu örnekteki kodun olması gerekenden açıkça daha ayrıntılı olduğunu unutmayın, ancak örneği daha açık hale getirdiğini düşündüm.


0

Aslında genel bir depo oluşturabilir ve bunun gibi bir şey yapabilirsiniz

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

}

ek: Microsoft.EntityFrameworkCore, FromSqlRaw içermez. Bu yöntemi kullanmak için Microsoft.EntityFrameworkCore.Relational'ı yüklemek gerekir.
Kate

-7

Entity Framework 6 ile aşağıdaki gibi bir şey çalıştırabilirsiniz

Modal Sınıfı oluştur

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 komutunu aşağıdaki gibi yürütün:

var userList = datacontext.Database.SqlQuery<User>(@"SELECT u.Id ,fname , lname ,username FROM dbo.Users").ToList<User>();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.