简体   繁体   中英

How to make an SQL query with custom columns in Entity Framework Core 5

I have some table like this:

CREATE TABLE names (
    score   INTEGER NOT NULL PRIMARY KEY,
    name    TEXT NOT NULL
);

And I want to get some stat from it. In sqlite I can use LEAD, but not there. I now about linq2db , but I wouldn't want to use it, because of its algorithm. As I understand it, this package does not add LEAD template to SQL conversion in EF linq, and executes the LEAD algorithm on its own side (not on the database side, which is more efficient). If I'm wrong, correct me.

For example, I want to execute query:

var lst = db.table_names.FromSqlRaw("SELECT score, LEAD(cid, 1) OVER (ORDER BY score) as next, LEAD(score, 1) OVER (ORDER BY score) - score AS diff FROM names ORDER BY diff DESC LIMIT 1");

This SQL-expression returns the two scores with the largest gap between them. The query is executed and returns a single row (known from lst.Count() and debugger).

The result is there, but how do I get it? Perhaps there is some feature of EF that allows to legally get data from the custom SQL-formed data structure?

I would not like to put crutches with filling in the class structure with the data I need to transmit to code, but not correct from the point of the purpose of the class fields.

Maybe there are illegal, but still less crutchy ways than the one I gave above?

You have two ways to approach this issue.

  1. Create a view on the database level with the query you have and use it in the entity framework, then you will be able to simply do the following
var lst = db.vw_name.OrderBy(d => d.diff).ToList();
  1. Use LINQ Query Syntax instead, but you will need to write multiple queries and join them together, as well as creating a new class that the query can use to instantiate a list of objects of. Here is a simplified example that does not contain SQL functions
public class Scores {
    public int Score { get; set; }
    public int Next { get; set; }
    public int Max { get; set; }
}

and

var lst = (from x in db.table_names
           orderby x.diff
           select new Scores {
               Score = x.score,
               Next = x.next,
               Max = x.Max
          }).ToList();

The former approach is much better for many reasons in my opinion.

Addition to answer from Bassel Ashi :

Create a view on the database level with the query you have and use it in the entity framework

Create a view on the database level:

db.Database.ExecuteSqlRaw(@"CREATE VIEW View_scoreDiff AS SELECT score, LEAD(cid, 1) OVER (ORDER BY score) as next, LEAD(score, 1) OVER (ORDER BY score) - score AS diff FROM names ORDER BY diff DESC LIMIT 1");

Then you need to create a class:

public class View_scoreDiffClass {
    public int Score { get; private set; }
    public int Next { get; private set; }
    public int Diff { get; private set; }
}

Add next field to your context:

public DbSet<View_scoreDiffClass> View_scoreDiff { get; private set; }

Add the following line to OnModelCreating :

modelBuilder.Entity<View_scoreDiffClass>().ToView("View_scoreDiff").HasNoKey();

After all this, you can execute db.View_scoreDiff.FirstOrDefault() and get the desired columns.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM