entityframework学习笔记--009-使用原生sql语句操作数据

时间:2021-08-25 11:11:24

1 使用原生SQL语句更新--Database.ExecuteSqlCommand

假设你有一张如图9-1所示的Payment数据库表。

entityframework学习笔记--009-使用原生sql语句操作数据

图9-1

1.1 实体类型:

  public class Payment
{
public int PaymentId { get; set; }
public decimal Amount { get; set; } public string Vendor { get; set; }
}

1.2 数据访问类:

 public class EF6RecipesContext: DbContext
{
public DbSet<Payment> Payments { get; set; }
public EF6RecipesContext()
: base("name=EF6CodeFirstRecipesContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<Payment>().ToTable("Payments", "example9");
}
}

1.3 代码演示:

 // 删除之前的测试数据
using (var context = new EFRecipesEntities())
{
context.Database.ExecuteSqlCommand("delete from chapter3.payment");
}
//插入两行数据
using (var context = new EFRecipesEntities())
{
var sql = @"insert into Chapter3.Payment(Amount, Vendor)
values (@Amount, @Vendor)"; //这里可以使用@p0这样的参数占位符,ado.net为自动为我们创建参数对象
var parameters = new DbParameter[]
{
new SqlParameter {ParameterName = "Amount", Value = 99.97M},
new SqlParameter {ParameterName = "Vendor", Value = "Ace Plumbing"}
}; var rowCount = context.Database.ExecuteSqlCommand(sql, parameters); parameters = new DbParameter[]
{
new SqlParameter {ParameterName = "Amount", Value = 43.83M},
new SqlParameter
{
ParameterName = "Vendor",
Value = "Joe's Trash Service"
}
}; rowCount += context.Database.ExecuteSqlCommand(sql, parameters);
Console.WriteLine("{0} rows inserted", rowCount.ToString());
} // 获取并显示数据
using (var context = new EFRecipesEntities())
{
Console.WriteLine("Payments");
Console.WriteLine("========");
foreach (var payment in context.Payments)
{
Console.WriteLine("Paid {0} to {1}", payment.Amount.ToString(),
payment.Vendor);
}
} Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();

输出:

1 2 rows inserted
2 Payments
3 ========
4 Paid $99.97 to Ace Plumbing
5 Paid $43.83 to Joe's Trash Service

2 使用原生SQL语句获取对象--Database.SqlQuery()

假设你有如图所示的一个拥有Student实体类型的模型。

entityframework学习笔记--009-使用原生sql语句操作数据

2.1 实体类型

public class Student
{
public int StudentId { get; set; }
public string Degree { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

2.2 上下文对象DbContext

 public class EFRecipesEntities : DbContext
{
public EFRecipesEntities()
: base("ConnectionString")
{
} public DbSet<Student> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>().ToTable("example9.Students");
base.OnModelCreating(modelBuilder);
}
}

2.3 代码演示:

 using (var context = new EFRecipesEntities())
{
// 删除出测试数据
context.Database.ExecuteSqlCommand("delete from example9.students"); // 插入数据
context.Students.Add(new Student
{
FirstName = "Robert",
LastName = "Smith",
Degree = "Masters"
});
context.Students.Add(new Student
{
FirstName = "Julia",
LastName = "Kerns",
Degree = "Masters"
});
context.Students.Add(new Student
{
FirstName = "Nancy",
LastName = "Stiles",
Degree = "Doctorate"
});
context.SaveChanges();
} using (var context = new EFRecipesEntities())
{
var sql = "select * from example9.Students where Degree = @Major";
var parameters = new DbParameter[]
{
new SqlParameter {ParameterName = "Major", Value = "Masters"}
};
var students = context.Database.SqlQuery<Student>(sql, parameters);
Console.WriteLine("Students...");
foreach (var student in students)
{
Console.WriteLine("{0} {1} is working on a {2} degree",
student.FirstName, student.LastName, student.Degree);
}
} Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();
}

输出:

 Students...
Robert Smith is working on a Masters degree
Julia Kerns is working on a Masters degree 这里在查询语句中使用“*”表示所有的列名,实体框架会将返回的列匹配到合适的属性上。一般情况下,这会工作得很好。但是,查询中只有部分列返回时,实体框架会在实例化对象时抛出一个异常。一个更好的方法和最佳实践是,在你的查询语句中显式枚举所有列(也就是说,指定所有的列名)。

  如果你的SQL语句返回的列多于实例化实体所需数量(也就是说,列值数量多于实体对象属性数量),实体框架会忽略掉多于的列。如果你仔细想想,这不是一个令人满意的行为。再一次重申,在SQL语句中显式枚举你所期望返回的列名,确保它们与实体类型匹配

  SqlQuery()方法有很多限制,如果你在使用TPH继承映射,你的SQL语句返回的行要映射到不同的派生类型上,实体框架不能使用鉴别列来将行映射到正确的派生类型。你可能会得到一个运行时异常,因为行中可能不包含正在实例化类型所需的值。

  有趣的是,我们可以使用SqlQuery()方法实例化根本就不是实体的类型。例如,我们创建一个StudentName类,它只包含姓,和名两个属性民。如果我们的SQL语句也只返回这两个列,我们可以使用SqlQuery<StudentName>()方法和指定的SQL语句获取类型StudentName的实例集合。

  我们很小心地使用短语,SQL语句,而不是查询语句,是因为SqlQuery()方法可以接受任何返回行集合的SQL语句。这当然包含查询语句,但也包含执行存储过程的SQL语句。