zoukankan      html  css  js  c++  java
  • Entity Framework 4 in Action读书笔记——第四章:使用LINQ to Entities查询:执行手动查询

    4.8 执行手动查询

    有很多原因决定你会手动写查询。或许由EF生成的SQL太慢,又或许执行起来浪费了太多资源。另一种情况可能是当你动态生成一个如此复杂的查询,创建SQL代码比使用LINQ to Entities简单。

    在这种情况下,你自己可以使用ObjectContext类的ExecuteStoreQuery<T>创建一个SQL命令。它允许你发出任意的查询并将查询结果映射到类。它的使用如下:

    var details = ctx.ExecuteStoreQuery<OrderDetail>("Select * from OrderDetail");

    就是这么简单。查询被执行,列自动映射到实体。关于映射阶段有一个小小的提示:它绕过了EDM,而是使用另外一种基于属性-列名匹配的机制。这一行为如图:

    image

    这个映射解决方案的有一定的局限性:

    1.如果一个属性跟相应的列名称不同,映射就不会执行并抛出异常。你可以很容易的通过在查询中使用AS SQL子句重命名列解决这个问题。
    2.不能映射到有复杂属性的实体,因为没有办法将复杂属性内的名称和列进行匹配。

    当然,你可以映射返回的数据到任何类型的类,不仅仅是那些定义在EDM中的。假设,你创建了一个类OrderDetailProjection,有Quantity,UnitPrice和Discount属性。你可以写一个查询,从OrderDetail表中取出Quantity, UnitPrice和 Discount列,并将结果映射到OrderDetailProjection。

    public class OrderDetailProjection
    {
        public int Quantity { get; set; }
        public decimal UnitPrice { get; set; }
        public decimal Discount { get; set; }
    }
    var details = ctx.ExecuteStoreQuery<OrderDetailProjection>
                 ("Select quantity, unitprice, discount from OrderDetail");

    注意:

    通过ExecuteStoreQuery<T>,你也可以启动存储过程。但是我们不建议这样做,因为EF本身就支持存储过程并且提供了比ExecuteStoreQuery<T>更多的选项。

    如果查询带有参数,你可以使用ExecuteStoreQuery<T>的重载方法,它接受参数列表。这可能会非常棘手,所以让我们看一看。

    4.8.1 带参数的查询

    当初EF团队设计如何传递参数时,有很多的选择。通过选择,现在有两种操作参数的方式。

    1.使用带有编号列表,跟String.Format方法一样。
    2.使用ADO.NET语法

    下面,我们详细看一下这两种方式。

    使用带编号的列表

    这是最简单的办法。在SQL查询中,将数字放在花括号中代表参数。然后,你在方法的第二个参数中传递参数。参数既可以是简单的数值也可以是DbParameter类的实例。这里有一些建议,要牢记:

    1.如果你使用DbParameter实例,你必须使用与数据库Provider相应的具体类型。例如,如果对SQL Server就必须使用SqlParameter,对OLE DB就必须使用OleDbParameter。如果你使用其他的实例,在运行时会得到InvalidCastException。

    2.如果你有多个参数,你不能混用DbParameter实例和纯值。你必须选择其一。否则,在运行时会得到InvalidOperationException。

    3.如果你使用简单的数值作为参数,它们传过来的顺序必须和它们在查询中的顺序一样。

    使用简单数值传递参数

    var names = ctx.ExecuteStoreQuery<string>
        ("SELECT name FROM company WHERE shippingcity = {0} and billingcity = {1}", "New York", "Seattle");

    使用SqlParameter传递参数

    var p0 = new SqlParameter("p0", DbType.String) { Value = "New York" };
    var p1 = new SqlParameter("p1", DbType.String) { Value = "Seattle" };
    var names = ctx.ExecuteStoreQuery<string>("SELECT name FROM company WHERE shippingcity = {0} and billingcity = {1}", p0, p1);

    正如你所见,这里没有什么特别困难的。只要注意我们前面提到的陷阱即可。

    注意:

    即使此语法可能会导致你认为可以通过SQL注入攻击的影响,但绝对不是这种情况。参数往往作为安全的方式传递给数据库。

    现在,让我们继续谈谈使用传统的参数

    使用传统的参数

    通过经典的ADO.NET写查询时,你通常写这样的东西表达参数:

    SELECT * FROM table WHERE id = @id

    这种语法对SQL Server provider是有效的。如果你使用OLE DB provider,你必须问号(?)代替@paramname。

    这种方法使用ExecuteStoreQuery<T>方法仍然完全有效。不是将数字放在花括号中,而是放置参数。其他都一样。参数的值仍然可以作为简单数值或参数传递过来。

    使用简单数值传递参数

    var names = ctx.ExecuteStoreQuery<string>
                ("SELECT name FROM company WHERE shippingcity = @p0 and billingcity = @p1",
                "New York", "Seattle");

    使用SqlParameter传递参数

    var p0 = new SqlParameter("p0", DbType.String) { Value = "New York" };
    var p1 = new SqlParameter("p1", DbType.String) { Value = "Seattle" };
    var names = ctx.ExecuteStoreQuery<string>
    ("SELECT name FROM company WHERE shippingcity = @p0 and billingcity = @p1", p0, p1);
    如果将这段代码和前面的代码比较,你会发现只是SQL代码中参数声明发生了改变。剩下的仍然是相同的,也就是说,没有更多的东西需要学习。

    到目前为止,我们已经介绍了如何编写功能强大的查询。现在,我们换个角度思考:你有多少相关的实体需要查询?是直接检索出所有相关的实体,还是根据代码需要。这显然是一个获取(fetching)问题,它几乎独立与你写的任何查询。

  • 相关阅读:
    POJ 2018 二分
    873. Length of Longest Fibonacci Subsequence
    847. Shortest Path Visiting All Nodes
    838. Push Dominoes
    813. Largest Sum of Averages
    801. Minimum Swaps To Make Sequences Increasing
    790. Domino and Tromino Tiling
    764. Largest Plus Sign
    Weekly Contest 128
    746. Min Cost Climbing Stairs
  • 原文地址:https://www.cnblogs.com/nianming/p/2179238.html
Copyright © 2011-2022 走看看