EF的多元化

EF支持多种查询语法:SQL查询、LinQ查询、Lambda表达式
EF会自动把Where()、OrderBy()、Select()等这些编译成“表达式树(Expression Tree)”,然后会把表达式树翻译成SQL语句去执行。(编译原理,AST)因此不是“把数据都取到内存中,然后使用集合的方法进行数据过滤”,因此性能不会低。但是如果这个操作不能被翻译成SQL语句,则或者报错,或者被放到内存中操作,性能就会非常低。

正执行的SQL语句

DbContext有一个Database属性,其中的Log属性,是Action委托类型,也就是可以指向一个void A(string s)方法,其中的参数就是执行的SQL语句,每次EF执行SQL语句的时候都会执行Log。因此就可以知道执行了什么SQL。
EF的查询是“延迟执行”的,只有遍历结果集的时候才执行select 查询,ToList()内部也是遍历结果集形成List。

EF是跨数据库的

如果迁移到MYSQL上,就会翻译成MYSQL的语法。要配置对应数据库的Entity Framework Provider。

细节

每次开始执行的__MigrationHistory等这些SQL语句是什么?是DBMigration用的,也就是由EF帮我们建数据库,现在我们用不到,用下面的代码禁用:

 public InLettDbContext() : base("name=con")
        {
            Database.SetInitializer<InLettDbContext>(null);
        }

XXXDbContext就是项目DbContext的类名。一般建议放到XXXDbContext构造函数中。注意这里的Database是System.Data.Entity下的类,不是DbContext的Database属性。如果写到DbContext中,最好用上全名,防止出错。

执行原始SQL

不要“手里有锤子,到处都是钉子”在一些特殊场合,需要执行原生SQL。
执行非查询语句,调用DbContext的Database属性的ExecuteSqlCommand方法,可以通过占位符的方式传递参数:

int res = context.Database.ExecuteSqlCommand("Update Students Set Pwd={1} where Id={0}", 1, "qwe");

占位符的方式不是字符串拼接,经过观察生成的SQL语句,发现仍然是参数化查询,因此不会有SQL注入漏洞。

DbRawSqlQuery<Student> list= context.Database.SqlQuery<Student>("SELECT * FROM Students WHERE Name={0}","张三");
List<Student> stus = list.ToList();

类似于ExecuteScalar的操作比较麻烦。

不是所有lambda写法都能被支持

下面想把Id转换为字符串比较一下是否为"1"(别管为什么):

IQueryable<Student> iqstu=  context.Students.Where(stu=>Convert.ToString(stu.Id)=="1");

运行会报错(也许高版本支持了就不报错了),这是一个语法、逻辑上合法的写法,但是EF目前无法把他解析为一个SQL语句。
出现“System.NotSupportedException”异常一般就说明你的写法无法翻译成SQL语句
想获取创建日期早于当前时间一小时以上的数据:

var result = context.Students.Where(p => (DateTime.Now - p.CreateTime).TotalHours>1);

同样也可能会报错。
怎么解决?
尝试其他替代方案(没有依据,只能乱试)
EF中提供了一个SQLServer专用的类SqlFunctions,对于EF不支持的函数提供了支持,比如:

var result = context.Students.Where(p =>SqlFunctions.DateDiff("hour",p.CreateTime,DateTime.Now)>1)

猜你喜欢

转载自blog.csdn.net/dust__/article/details/106491288