Methods EFCore execute Sql statement: FromSql and ExecuteSqlCommand

Foreword

Sql statement in the method performed as EFCore: FromSql and ExecuteSqlCommand; SqlQuery with ExecuteSqlCommand as in the EF6, while FromSql SqlQuery very different and, FromSql IQueryable return value, and therefore the delay of loading, Linq extension method can be used with use, but there are a lot of pit (EFCore version 1.1.0), it is recommended to perform direct Sql statements do not use FromSql, but EFCore and does not provide SqlQuery method, so the following will be posted SqlQuery implementation code for your reference, in order to It can be used in EFCore in.

FromSql and ExecuteSqlCommand use

When tested using the SqlServer2008 and SqlServer Profiler Sql statements were captured, EFCore version is 1.1.0.

Entity Model and DbContext test

public class MSSqlDBContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"data source=localhost;initial catalog=TestDB;Integrated Security=True;");
        }
        public DbSet<Person> Person { get; set; }
        public DbSet<Address> Address { get; set; }
}

    [Table(nameof(Person))]
    public class Person
    {
        public int id { get; set; }
        public string name { get; set; }
        [Column(TypeName = "datetime")]
        public DateTime? birthday { get; set; }
        public int? addrid { get; set; }
}

    [Table(nameof(Address))]
    public class Address
    {
        public int id { get; set; }
        public string fullAddress { get; set; }
        public double? lat { get; set; }
        public double? lon { get; set; }
    }

  

ExecuteSqlCommand

EFCore of ExecuteSqlCommand and EF6 like, Sql statements executed non-query:

var db = new MSSqlDBContext();
2             db.Database.ExecuteSqlCommand($"update {nameof(Person)} set name=@name where id=@id", new[] 
3             {
4                 new SqlParameter("name", "tom1"),
5                 new SqlParameter("id", 1),
6             });

  

FromSql

The official reference documentation: https://docs.microsoft.com/en-us/ef/core/querying/raw-sql

Simple to use

 var db = new MSSqlDBContext();
2             var name = "tom";
3             var list = db.Set<Person>().FromSql($"select * from {nameof(Person)} where {nameof(name)}=@{nameof(name)} ", 
4                 new SqlParameter(nameof(name), name)).ToList();

  Generated Sql:

exec sp_executesql N'select * from Person where name=@name 
',N'@name nvarchar(3)',@name=N'tom'

  

note:

Generated by default for the Person of the Model, if not included in a Person Field Select acquired will throw an exception, for example: the following statement to obtain only the name field, and does not include other fields Person, then throw an exception: The required column 'id' was not present in the results of a 'FromSql' operation.

 

db.Set<Person>().FromSql($"select name from {nameof(Person)} ").ToList();

  Then read:

db.Set<Person>().Select(l => l.name).FromSql($"select name from {nameof(Person)} ").ToList();

  

Execute stored procedures

 var db = new MSSqlDBContext();
db.Set<Person>().FromSql("exec testproc @id", new SqlParameter("id", 1)).ToList();

  Generated Sql:

exec sp_executesql N'exec testproc @id
',N'@id int',@id=1

  

Linq extension method used in conjunction with the

var db = new MSSqlDBContext();
db.Set<Person>().FromSql($"select * from {nameof(Person)} where name=@name ", new SqlParameter("@name", "tom"))
                .Select(l => new { l.name, l.birthday }).ToList();

  Generated Sql:

exec sp_executesql N'SELECT [l].[name], [l].[birthday]
FROM (
    select * from Person where name=@name 
) AS [l]',N'@name nvarchar(3)',@name=N'tom'

  

inner join + order by

var db = new MSSqlDBContext();
              (from p in db.Set<Person>().FromSql($"select * from {nameof(Person)} ")
              join a in db.Set<Address>().Where(l => true)
              on p.addrid equals a.id
              select new { p.id, p.name, a.fullAddress }).OrderBy(l => l.id).ToList();

  Generated Sql:

SELECT [p].[id], [p].[name], [t].[fullAddress]
FROM (
    select * from Person 
) AS [p]
INNER JOIN (
    SELECT [l0].*
    FROM [Address] AS [l0]
) AS [t] ON [p].[addrid] = [t].[id]
ORDER BY [p].[id]

  

left join + order by

var db = new MSSqlDBContext();
              (from p in db.Set<Person>().FromSql($"select * from {nameof(Person)} ")
              join a in db.Set<Address>().Where(l => true)
             on p.addrid equals a.id into alist
              from a in alist.DefaultIfEmpty()
              select new { p.id, p.name, fullAddress = a == null ? null : a.fullAddress }).OrderBy(l => l.id).ToList();

  Generated Sql :( Sql generated very problematic, order by after more than [p]. [Addrid], and select the field is also generated more)

SELECT [p].[id], [p].[addrid], [p].[birthday], [p].[name], [t].[id], [t].[fullAddress], [t].[lat], [t].[lon]
FROM (
    select * from Person 
) AS [p]
LEFT JOIN (
    SELECT [l0].[id], [l0].[fullAddress], [l0].[lat], [l0].[lon]
    FROM [Address] AS [l0]
) AS [t] ON [p].[addrid] = [t].[id]
ORDER BY [p].[id], [p].[addrid]

  The FromSql replaced Where extension method to try:

             (from p in db.Set<Person>().Where(l => true)
              join a in db.Set<Address>().Where(l => true)
              on p.addrid equals a.id into alist
              from a in alist.DefaultIfEmpty()
              select new { p.id, p.name, fullAddress = a == null ? null : a.fullAddress }).OrderBy(l => l.id).ToList();

  EFCore generated Sql (order by more than a back or [addrid], select the field is also more):

SELECT [l].[id], [l].[addrid], [l].[birthday], [l].[name], [t].[id], [t].[fullAddress], [t].[lat], [t].[lon]
FROM [Person] AS [l]
LEFT JOIN (
    SELECT [l1].[id], [l1].[fullAddress], [l1].[lat], [l1].[lon]
    FROM [Address] AS [l1]
) AS [t] ON [l].[addrid] = [t].[id]
ORDER BY [l].[id], [l].[addrid]

  In EF6 generated Sql, generating better than EFCore:

SELECT 
    [Project1].[id] AS [id], 
    [Project1].[name] AS [name], 
    [Project1].[C1] AS [C1]
    FROM ( SELECT 
        [Extent1].[id] AS [id], 
        [Extent1].[name] AS [name], 
        CASE WHEN ([Extent2].[id] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE [Extent2].[fullAddress] END AS [C1]
        FROM  [dbo].[Person] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Address] AS [Extent2] ON [Extent1].[addrid] = [Extent2].[id]
    )  AS [Project1]
    ORDER BY [Project1].[id] ASC

  

Description result

FromSql can not replace the original SqlQuery use EF6, and when combined with Linq extension methods used to generate the Sql there will be some problems (EFCore version: 1.1.0), then in order to be able to execute a query in Sql EFCore provided the following method for SqlQuery implementation.

SqlQuery implementation

static the IList public <T> The SqlQuery <T> (DbContext DB, String SQL, the params Object [] Parameters) 
            WHERE T: new new () 
        { 
            // NOTE: Do not GetDbConnection conn performed using the acquired or calls Dispose, or subsequent DbContext can no longer be used, and will throw exception 
            var db.Database.GetDbConnection Conn = (); 
            the try 
            { 
                conn.Open (); 
                the using (Command = conn.CreateCommand var ()) 
                { 
                    command.CommandText = SQL; 
                    command.Parameters. the AddRange (Parameters); 
                    var propts = typeof (T) .GetProperties (); 
                    var = rtnList new new List <T> (); 
                    T Model; 
                    Object Val;
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            model = new T();
                            foreach (var l in propts)
                            {
                                val = reader[l.Name];
                                if (val == DBNull.Value)
                                {
                                    l.SetValue(model, null);
                                }
                                else
                                {
                                    l.SetValue(model, val);
                                }
                            }
                            rtnList.Add(model);
                        }
                    }
                    return rtnList;
                }
            }
            finally
            {
                conn.Close();
            }
        }

  use:

var db = new MSSqlDBContext();
            string name = "tom";
            var list = SqlQuery<PAModel>(db,
                $" select p.id, p.name, a.fullAddress, a.lat, a.lon " +
                $" from ( select * from {nameof(Person)} where {nameof(name)}=@{nameof(name)} ) as p " +
                $" left join {nameof(Address)} as a on p.addrid = a.id ",
                new[] { new SqlParameter(nameof(name), name) });

  Generated Sql:

exec sp_executesql N' select p.id, p.name, a.fullAddress, a.lat, a.lon  from ( select * from Person where name=@name ) as p  left join Address as a on p.addrid = a.id ',N'@name nvarchar(3)',@name=N'tom'

  

Guess you like

Origin www.cnblogs.com/jiangyunfeng/p/11729846.html