1 使用原生SQL语句更新--Database.ExecuteSqlCommand
假设你有一张如图9-1所示的Payment数据库表。
图9-1
1.1 实体类型:
1 public class Payment 2 { 3 public int PaymentId { get; set; } 4 public decimal Amount { get; set; } 5 6 public string Vendor { get; set; } 7 }
1.2 数据访问类:
1 public class EF6RecipesContext: DbContext 2 { 3 public DbSet<Payment> Payments { get; set; } 4 public EF6RecipesContext() 5 : base("name=EF6CodeFirstRecipesContext") 6 { 7 } 8 protected override void OnModelCreating(DbModelBuilder modelBuilder) 9 { 10 base.OnModelCreating(modelBuilder); 11 12 modelBuilder.Entity<Payment>().ToTable("Payments", "example9"); 13 } 14 }
1.3 代码演示:
1 // 删除之前的测试数据 2 using (var context = new EFRecipesEntities()) 3 { 4 context.Database.ExecuteSqlCommand("delete from chapter3.payment"); 5 } 6 //插入两行数据 7 using (var context = new EFRecipesEntities()) 8 { 9 var sql = @"insert into Chapter3.Payment(Amount, Vendor) 10 values (@Amount, @Vendor)"; //这里可以使用@p0这样的参数占位符,ado.net为自动为我们创建参数对象 11 var parameters = new DbParameter[] 12 { 13 new SqlParameter {ParameterName = "Amount", Value = 99.97M}, 14 new SqlParameter {ParameterName = "Vendor", Value = "Ace Plumbing"} 15 }; 16 17 var rowCount = context.Database.ExecuteSqlCommand(sql, parameters); 18 19 parameters = new DbParameter[] 20 { 21 new SqlParameter {ParameterName = "Amount", Value = 43.83M}, 22 new SqlParameter 23 { 24 ParameterName = "Vendor", 25 Value = "Joe‘s Trash Service" 26 } 27 }; 28 29 rowCount += context.Database.ExecuteSqlCommand(sql, parameters); 30 Console.WriteLine("{0} rows inserted", rowCount.ToString()); 31 } 32 33 // 获取并显示数据 34 using (var context = new EFRecipesEntities()) 35 { 36 Console.WriteLine("Payments"); 37 Console.WriteLine("========"); 38 foreach (var payment in context.Payments) 39 { 40 Console.WriteLine("Paid {0} to {1}", payment.Amount.ToString(), 41 payment.Vendor); 42 } 43 } 44 45 Console.WriteLine("\nPress <enter> to continue..."); 46 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实体类型的模型。
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
1 public class EFRecipesEntities : DbContext 2 { 3 public EFRecipesEntities() 4 : base("ConnectionString") 5 { 6 } 7 8 public DbSet<Student> Students { get; set; } 9 10 protected override void OnModelCreating(DbModelBuilder modelBuilder) 11 { 12 modelBuilder.Entity<Student>().ToTable("example9.Students"); 13 base.OnModelCreating(modelBuilder); 14 } 15 }
2.3 代码演示:
1 using (var context = new EFRecipesEntities()) 2 { 3 // 删除出测试数据 4 context.Database.ExecuteSqlCommand("delete from example9.students"); 5 6 // 插入数据 7 context.Students.Add(new Student 8 { 9 FirstName = "Robert", 10 LastName = "Smith", 11 Degree = "Masters" 12 }); 13 context.Students.Add(new Student 14 { 15 FirstName = "Julia", 16 LastName = "Kerns", 17 Degree = "Masters" 18 }); 19 context.Students.Add(new Student 20 { 21 FirstName = "Nancy", 22 LastName = "Stiles", 23 Degree = "Doctorate" 24 }); 25 context.SaveChanges(); 26 } 27 28 using (var context = new EFRecipesEntities()) 29 { 30 var sql = "select * from example9.Students where Degree = @Major"; 31 var parameters = new DbParameter[] 32 { 33 new SqlParameter {ParameterName = "Major", Value = "Masters"} 34 }; 35 var students = context.Database.SqlQuery<Student>(sql, parameters); 36 Console.WriteLine("Students..."); 37 foreach (var student in students) 38 { 39 Console.WriteLine("{0} {1} is working on a {2} degree", 40 student.FirstName, student.LastName, student.Degree); 41 } 42 } 43 44 Console.WriteLine("\nPress <enter> to continue..."); 45 Console.ReadLine(); 46 }
输出:
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语句。
时间: 2024-10-26 19:30:12