DbSet के बिना रॉ SQL क्वेरी - एंटिटी फ्रेमवर्क कोर


107

एंटिटी फ्रेमवर्क कोर हटाने के साथ dbData.Database.SqlQuery<SomeModel>मैं अपने पूर्ण-पाठ खोज क्वेरी के लिए एक कच्ची एसक्यूएल क्वेरी बनाने के लिए एक समाधान नहीं ढूंढ सकता हूं जो टेबल डेटा और रैंक भी लौटाएगा।

एंटिटी फ्रेमवर्क कोर में एक कच्ची एसक्यूएल क्वेरी बनाने के लिए मैंने जो एकमात्र तरीका देखा dbData.Product.FromSql("SQL SCRIPT");है, वह उपयोगी नहीं है क्योंकि मेरे पास कोई डीबीसेट नहीं है जो क्वेरी में वापस आने वाले रैंक को मैप करेगा।

कोई विचार???


15
मैं SqlQuery <T> को बहुत याद करूंगा और कस्टम क्लास को मेरे DbContext पर मैप करना नहीं चाहता, जब मुझे वास्तव में एक विशिष्ट उपयोग के मामले के लिए एक साधारण डीटीओ की आवश्यकता होती है। मैंने इस फीचर को वापस EF Core में जोड़ने के लिए एक उपयोगकर्ता की आवाज बनाई है कि कोई भी वोट दे सकता है यदि वे इस सुविधा को वापस चाहते हैं: data.uservoice.com/forums/…
मैट सैंडर्स

1
Github.com/aspnet/EntityFramework/issues/1862 के अनुसार , यह अब EF कोर 1.2 और / या 1.1.0-पूर्वावलोकन 1 के लिए लक्षित है
डैन फील्ड

2
@Devon ने जो कुछ भी कहा था, उस पर निर्माण करते हुए, मैंने अभी बहुत लंबा समय बिताया है और यह पता लगाया है कि वे Microsoft में विस्तार विधियाँ हैं। EntityFrameworkCore.SqlServer इन विस्तार विधियों को प्राप्त करने से पहले आपको इसे अपनी परियोजना में जोड़ना होगा।
डैनियल

3
आह इस वास्तुकला अंतरिक्ष यात्री निर्णय किसी तरह की तरह लगता है: "लोगों को इस चाहते हैं की जरूरत नहीं करना चाहिए"। मुझे लगता है कि मुझे इस मामले के लिए डैपर को स्थापित करना होगा। कष्टप्रद।
डर्क बोअर

1
@MattSanders - आप uservoice लिंक कर रहे हैं कि इस बीच मृत हो गया। क्या आप जानते हैं कि यह कहां गया?
डर्क बोअर

जवाबों:


126

यह निर्भर करता है कि आप EF Core 2.1 या EF Core 3 और उच्चतर संस्करणों का उपयोग कर रहे हैं ।

यदि आप EF Core 2.1 का उपयोग कर रहे हैं

यदि आप 7 मई 2018 से उपलब्ध ईएफ कोर 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();

यह भी ध्यान रखें कि DdContextरों हैं आंशिक वर्गों , ताकि आप सबसे अच्छा आप सूट के रूप में अपने 'कच्चे एसक्यूएल DbQuery' परिभाषा व्यवस्थित करने के लिए एक या अधिक अलग फ़ाइलों बना सकते हैं।


यदि आप EF Core 3.0 और उच्चतर संस्करण का उपयोग कर रहे हैं

क्वेरी प्रकार अब बिना चाबी के प्रकार के रूप में जाना जाता है । जैसा कि ऊपर कहा गया है कि ईएफ कोर 2.1 में क्वेरी प्रकार पेश किए गए थे। यदि आप EF Core 3.0 या उच्चतर संस्करण का उपयोग कर रहे हैं, तो आपको अब बिना चाबी के टेंटिटी प्रकारों का उपयोग करके कंडोम करना चाहिए क्योंकि क्वेरी प्रकार अब अप्रचलित हैं।

यह सुविधा क्वेरी प्रकारों के नाम के तहत ईएफ कोर 2.1 में जोड़ी गई थी। ईएफ कोर 3.0 में अवधारणा को बिना चाबी इकाई प्रकारों में बदल दिया गया था। [Keyless] डाटा एनोटेशन EFCore 5.0 में उपलब्ध हो गया।

हमारे पास अभी भी उसी प्रकार के परिदृश्य हैं जो क्वेरी प्रकारों के लिए हैं जब बिना चाबी इकाई प्रकार का उपयोग करना है।

तो इसका उपयोग करने के लिए आपको पहले अपनी कक्षा SomeModelको [Keyless]डेटा एनोटेशन के साथ या .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();

18
ईएफ कोर 2.1 और इसके बाद के संस्करण का उपयोग करते समय यह उत्तर सबसे अच्छा समाधान होना चाहिए। 👍
हुआंग

2
@CodeNotFound क्या होगा यदि मुझे परिणाम की आवश्यकता नहीं है या यदि यह एक आदिम प्रकार है (उदाहरण के लिए bit)?
शिम्मी वेइटहैंडलर

5
CodeFirst का उपयोग करके यह स्वचालित रूप से उन सभी गुणों के साथ एक तालिका बनाता है, [NotMapped]जो SomeModelsवर्ग में जोड़ने से मेरे लिए काम नहीं करता है। क्या मैं कुछ भूल गया?
जीन-पॉल

7
ईएफ कोर 3.0 बिना चाबी इकाई प्रकारों के साथ DbQueryउपयोग करने के पक्ष में दर्शाया गया हैDbSet
नेटमैज नोव

3
बस FYI करें, EF कोर 3.0 में कुछ बग के कारण, कोड-प्रथम माइग्रेशन अभी भी HasNoKey () के साथ चिह्नित संस्थाओं पर भी एक तालिका बनाने का प्रयास करेगा। तो आपको भी जोड़ना है ।ToView (नल)। जैसे modelBuilder.Entity<MyData>().HasNoKey().ToView(null);@ जीन-पॉल मुझे लगता है कि यह आपके मुद्दे को हल करता है
stann1

36

उदाहरण के उपयोग सहित कार्य को पूरा करने वाले इस सहायक को लिखे गए अन्य उत्तरों पर निर्माण करना:

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

उपयोग:

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 कोर टीम से आर्थर विकर्स के एक बयान के अनुसार यह पोस्ट 2.0 के लिए एक उच्च प्राथमिकता है। इस मुद्दे पर नज़र रखी जा रही है


अच्छा जवाब, अच्छा लगा।
sebu

31

EF Core में अब आप "मुफ्त" कच्चे sql को निष्पादित नहीं कर सकते हैं। आपको एक POCO वर्ग और DbSetउस वर्ग के लिए परिभाषित करना आवश्यक है । आपके मामले में आपको रैंक परिभाषित करने की आवश्यकता होगी :

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

जैसा कि यह निश्चित रूप से आसानी से होगा यह .AsNoTracking()कॉल को शामिल करने के लिए उपयोगी होगा ।

EDIT - EF Core 3.0 में परिवर्तन

DbQuery () अब अप्रचलित है, इसके बजाय DbSet () का उपयोग किया जाना चाहिए (फिर से)। यदि आपके पास कीलेस एंटिटी है, तो इसे प्राथमिक कुंजी की आवश्यकता नहीं है, तो आप HasNoKey () विधि का उपयोग कर सकते हैं :

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

अधिक जानकारी यहां पाई जा सकती है


3
इसलिए मुझे लगता है कि मुझे DbContextएक नई संपत्ति को शामिल करने के लिए भी विस्तार करना होगा DbSet<Rank> Rank { get; set; }। अब लिनक के संदर्भ में इसके क्या निहितार्थ होंगे? यानी अब हम DBContext.Rank.Where(i => i.key == 1)इस तरह के एक बयान का उपयोग करने में सक्षम होंगे , और क्या इस कथन का एसक्यूएल में कोई क्रियान्वयन नहीं होगा और इसलिए विफल?
डेविड हरलो

इस सेट के खिलाफ उत्सर्जित लाइनक को स्मृति में हल किया जाना है। यदि आपको अलग-अलग WHERE एसक्यूएल क्लॉज का उत्सर्जन करने की आवश्यकता है, तो आपको उन्हें मापदंडों के रूप में शामिल करना होगा या एक अलग स्क्रिप्ट का निर्माण करना होगा।
ई-बैट

मेरे DbSet में "FromSql" विधि नहीं है। क्या यह एक्सटेंशन मुझे याद आ रहा है?
बीरविन

1
@ बैटविन, आपको नामस्थान Microsoft को आयात करने की आवश्यकता है। EntityFrameworkCore
E-Bat

20

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

18

अभी के लिए, EFCore से कुछ नया होने तक मैं एक कमांड का उपयोग करता था और इसे मैन्युअल रूप से मैप करता था

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

SqlParameter Sql Injection से बचने की कोशिश करें।

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

FromSql पूरी क्वेरी के साथ काम नहीं करता है। उदाहरण यदि आप WHERE क्लॉज़ को शामिल करना चाहते हैं तो इसे अनदेखा कर दिया जाएगा।

कुछ लिंक:

एंटिटी फ्रेमवर्क कोर का उपयोग करके कच्चे एसक्यूएल क्वेरी को निष्पादित करना

रॉ SQL क्वेरीज़


7

कोर 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;
}

इस तरह से रैंक मॉडल आपके DB में नहीं बनाया जाएगा।

अब आपके कंट्रोलर / एक्शन में आप कॉल कर सकते हैं:

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

इस तरह से आप Raw SQL प्रक्रिया को कॉल कर सकते हैं।


FromSqlपैरामीटर बस बनाने के बिना भी भेजी जा सकती SqlParameterवस्तु: FromSql($"STORED_PROCEDURE {value1}, {value2}")या FromSql("STORED_PROCEDURE {0}, {1}", value1, value2)(वे भाग निकले किया जाएगा)।
माजिद

7

आप इसे ( https://github.com/aspnet/EntityFrameworkCore/issues/1862#issuecomment-451671168 से ) का उपयोग कर सकते हैं :

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.Query<T>();
            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");
    }

6

Nuget पैकेज जोड़ें - Microsoft.EntityFrameworkCore.Relational

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

यह पंक्ति संख्याओं को एक इंट के रूप में लौटाएगा

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


3
कृपया ध्यान दें कि यह केवल कमांड द्वारा प्रभावित पंक्तियों की संख्या
लौटाएगा

वास्तव में मुझे क्या चाहिए। मैं Microsoft.EntityFrameworkCore 3.1.1 का उपयोग कर रहा हूं और रॉ क्वेरी और एसपी को निष्पादित करने का कोई तरीका नहीं है। इसके लिए आपको बहुत धन्यवाद!
jaysonragasa

5

इसे आज़माएँ: (विस्तार विधि बनाएँ)

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

उपयोग:

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

मेरा मॉडल: (में नहीं DbSet):

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

में परीक्षण किया गया .netCore 2.2 and 3.0

नोट: इस समाधान का प्रदर्शन धीमा है


पहले रिकॉर्ड के लिए केवल एक बार नाम से प्रॉपर्टीइन्फो सर्च करने की कोशिश करें और अगले रिकॉर्ड्स का उपयोग करने के लिए कॉलम इंडेक्स द्वारा प्रॉपर्टीइन्फो [] की सरणी बनाएं।
पेट्र वोबोनिर्क

@AminRostami अच्छा काम
sebu

2

सीधे ओपी के परिदृश्य को लक्षित नहीं कर रहा है, लेकिन जब से मैं इसके साथ संघर्ष कर रहा हूं, मैं इन पूर्व को छोड़ना चाहता हूं। कच्चे SQL को निष्पादित करने के लिए आसान तरीके 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

मैंने डापर का इस्तेमाल एंटिटी फ्रेमवर्क कोर के इस अवरोध को बायपास करने के लिए किया ।

IDbConnection.Query

कई मापदंडों के साथ sql क्वेरी या संग्रहीत कार्यविधि के साथ काम कर रहा है। वैसे यह थोड़ा तेज़ है ( बेंचमार्क टेस्ट देखें )

डॅपर सीखना आसान है। मापदंडों के साथ संग्रहीत प्रक्रिया को लिखने और चलाने में 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();
        }


        }
}

0

आप QueryFirst का उपयोग भी कर सकते हैं । डैपर की तरह, यह पूरी तरह से ईएफ के बाहर है। डैपर (या ईएफ) के विपरीत, आपको पीओसीओ बनाए रखने की आवश्यकता नहीं है, आप अपने एसक्यूएल एसक्यूएल को वास्तविक वातावरण में संपादित करते हैं, और यह लगातार डीबी के खिलाफ अमान्य है। अस्वीकरण: मैं QueryFirst का लेखक हूं।


0

मेरे मामले में कच्चे SQL के बजाय संग्रहीत प्रक्रिया का उपयोग किया गया

एक वर्ग बनाया

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

मेरी DbContextकक्षा में नीचे जोड़ा गया

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

संग्रहीत कार्यविधि निष्पादित करने के लिए:

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

0

मुझे पता है कि यह एक पुराना सवाल है, लेकिन हो सकता है कि यह किसी को डीटीओ के रूप में डीटीबी को जोड़े बिना संग्रहीत प्रक्रियाओं को कॉल करने में मदद करता है।

https://stackoverflow.com/a/62058345/3300944


0

यह समाधान @ पायस से समाधान पर भारी पड़ता है। मैं SQL इंजेक्शन को कम करने में मदद करने के लिए क्वेरी मापदंडों का समर्थन करने के लिए विकल्प जोड़ना चाहता था और मैं इसे एंटिटी फ्रेमवर्क कोर के लिए DbContext DatabaseFacade का एक विस्तार बंद करना चाहता था ताकि इसे थोड़ा और एकीकृत किया जा सके।

पहले एक्सटेंशन के साथ एक नया वर्ग बनाएं:

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

}

उपरोक्त में ध्यान दें कि "T" रिटर्न के लिए प्रकार है और "P" आपके क्वेरी मापदंडों का प्रकार है, जो इस आधार पर भिन्न होगा कि क्या आप MySql, Sql, इत्यादि का उपयोग कर रहे हैं।

आगे हम एक उदाहरण दिखाएंगे। मैं MySql EF Core क्षमता का उपयोग कर रहा हूं, इसलिए हम देखेंगे कि हम इस अधिक विशिष्ट MySql कार्यान्वयन के साथ जेनेरिक एक्सटेंशन का उपयोग कैसे कर सकते हैं:

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

क्वेरी पंक्तियों को लौटाएगी जैसे:
"Ford", "Explorer", "Ford Explorer"
"Tesla", "Model X", "Tesla Model X"।

प्रदर्शन शीर्षक को डेटाबेस कॉलम के रूप में परिभाषित नहीं किया गया है, इसलिए यह डिफ़ॉल्ट रूप से EF कार मॉडल का हिस्सा नहीं होगा। मैं इस दृष्टिकोण को कई संभावित समाधानों में से एक के रूप में पसंद करता हूं। इस पृष्ठ के अन्य उत्तर इस मुद्दे को संबोधित करने के अन्य तरीकों को संदर्भित करते हैं [नोटमैपेड] डेकोरेटर के साथ, जो आपके उपयोग के मामले के आधार पर अधिक उपयुक्त दृष्टिकोण हो सकता है।

ध्यान दें कि इस उदाहरण में कोड स्पष्ट रूप से अधिक क्रियात्मक है जितना कि इसकी आवश्यकता है, लेकिन मुझे लगा कि इसने उदाहरण को स्पष्ट कर दिया है।


-6

एंटिटी फ्रेमवर्क 6 के साथ आप नीचे की तरह कुछ निष्पादित कर सकते हैं

के रूप में मॉडल कक्षा बनाएँ

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

नीचे के रूप में कच्चे DQL SQl आदेश निष्पादित करें:

var userList = datacontext.Database.SqlQuery<User>(@"SELECT u.Id ,fname , lname ,username FROM dbo.Users").ToList<User>();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.