IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    EntityFramework 6 SqlQuery传递可空类型参数的写法

    汪宇杰发表于 2014-09-03 01:38:23
    love 0

    有时候我们需要在EF里直接执行参数化的SQL语句,如果有返回,就要把结果映射成C#对象集合。貌似是从EF4.2开始(4.0写法不一样)提供了DbContext.Database.SqlQuery()的API可以直接执行SQL。但是如果碰到可控类型的参数,比如Guid?,就会爆。

    看一个例子,定义的SQL语句如下:

    string sql = @"SELECT p2.Id                      AS PeriodId,
                          p2.Title                   AS PeriodTitle,
                          u.UserId                   AS UserId,
                          u.DisplayName              AS UserDisplayName,
                          p.Id                       AS ProductId,
                          p.Title                    AS ProductTitle,
                          SUM(upa.Amount)            AS TotalCount,
                          SUM(p.Price * upa.Amount)  AS TotalPrice,
                          upa.Note                   AS Note
                   FROM   Product                    AS p
                          INNER JOIN UserProductAssociation AS upa
                               ON  upa.ProductId = p.Id
                          INNER JOIN Orders          AS o
                               ON  o.Id = upa.OrderId
                          INNER JOIN Period          AS p2
                               ON  p2.Id = o.PeriodId
                          INNER JOIN Users           AS u
                               ON  u.UserId = o.UserId
                   WHERE  1 = 1
                          AND (@userId IS NULL OR u.UserId = @userId)
                          AND (@periodId IS NULL OR p2.Id = @periodId)
                   GROUP BY
                          u.UserId,
                          u.DisplayName,
                          p2.Id,
                          p2.Title,
                          p.Id,
                          p.Title,
                          upa.Note";
    

    其中@userId和@periodId均为Guid?类型的参数,比如传进来的时候是这样的:

    public ActionResult GetStatGridData(..., Guid? userId, Guid? periodId)
    ...

    如果你这样写:

    _db.Database.SqlQuery(sql, new[]
                {
                    userId, 
                    periodId
                }).ToList();

    就会爆成这样:

    No mapping exists from object type System.Nullable`1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][] to a known managed provider native type.

    查了一些资料,说是要转DBNull进去,于是你这样写:

    _db.Database.SqlQuery(sql, new[]
                {
                    userId ?? (object)DBNull.Value, 
                    periodId ?? (object)DBNull.Value
                }).ToList();

    结果还是爆:

    Must declare the scalar variable "@userId".

    最终发现,你得这样写:

    _db.Database.SqlQuery(sql,
                new SqlParameter("@userId", userId ?? (object)DBNull.Value),
                new SqlParameter("@periodId", periodId ?? (object)DBNull.Value)).ToList();

    就不会爆。

    另外,这种写法不适用于SQL CE (已在EF5 + SQL CE上zuo die过)。不知道这是EF的bug还是我SB。总之写下此文以警后人。



沪ICP备19023445号-2号
友情链接