SqlParameter已包含在另一个SqlParameterCollection中

时间:2013-03-09 08:34:16

标签: entity-framework-4 dbcontext sqlparameters pagedlist

我使用EF DbContext SqlQuery使用PagedList(https://github.com/TroyGoode/PagedList)获取分页对象列表,并且我收到以下错误:

" SqlParameter已经包含在另一个SqlParameterCollection"

这是我的存储库代码:

var db = (DbContext)DataContext;
        const string sqlString =
            @"            
            WITH UserFollowerList
            AS 
            ( 
            SELECT uf.FollowId
            FROM UserFollow uf 
            WHERE uf.UserId = @UserId
            )
            SELECT * FROM UserFollowerList uf
            INNER JOIN [User] u ON uf.FollowId = u.UserId
            WHERE IsDeleted = 0
            "
            ;

        var userIdParam = new SqlParameter("UserId", SqlDbType.Int) {Value = userId};

        var userList =
            db.Database.SqlQuery<User>(sqlString, userIdParam)
            .ToPagedList(pageIndex, pageSize);

        return userList;

但是当我在SqlQuery语句上调用ToList扩展时,它可以正常工作:

var userList = db.Database.SqlQuery<User>(sqlString, userIdParam).ToList();

PagedList代码:

private PagedList(IQueryable<T> source, int pageIndex, int pageSize)
    {
        TotalItemCount = source.Count();

        PageSize = pageSize;
        PageIndex = pageIndex;
        PageCount = TotalItemCount > 0 ? (int)Math.Ceiling(TotalItemCount / (double)PageSize) : 0;

        HasPreviousPage = (PageIndex > 0);
        HasNextPage = (PageIndex < (PageCount - 1));
        IsFirstPage = (PageIndex <= 0);
        IsLastPage = (PageIndex >= (PageCount - 1));

        ItemStart = PageIndex * PageSize + 1;
        ItemEnd = Math.Min(PageIndex * PageSize + PageSize, TotalItemCount);

        // add items to internal list
        if (TotalItemCount > 0)
            Data = pageIndex == 0 ? source.Take(pageSize).ToList() : source.Skip((pageIndex) * pageSize).Take(pageSize).ToList();
    }

我已经解决了以下问题而没有取得任何成功:

var param = new DbParameter[] { new SqlParameter { ParameterName = "UserId", Value = userId }

我该怎么做才能解决我遇到的错误?

6 个答案:

答案 0 :(得分:4)

当使用对SQL数据库的通用调用(例如db.Database.SqlQuery)时,必须迭代到返回的Set的最后一条记录,以便释放结果集和相关参数。 PagedList使用source.Take(pageSize).ToList(),它不会读到源集的末尾。您可以在返回结果之前通过执行类似foreach(userList中的用户x)之类的操作来解决此问题。

答案 1 :(得分:4)

仅供参考我在使用EF 5 DbContext使用SqlParameters数组调用context.ExecuteQuery<my_type>(...);时看到了完全相同的错误消息,其中my_type有string但SQL语句返回{{1}其中一个参数。

错误实际上是在返回映射中,但是它说SqlParameter是责备,这让我暂时离开。

答案 2 :(得分:0)

我在http://blogs.msdn.com/b/diego/archive/2012/01/10/how-to-execute-stored-procedures-sqlquery-in-the-dbcontext-api.aspx尝试了Diego Vega的以下解决方案,它对我有用:

 var person = context.Database.SqlQuery<Person>(
 "SELECT * FROM dbo.People WHERE Id = {0}", id);

答案 3 :(得分:0)

当你在(SqlQuery或ExecuteSqlCommand)上使用参数时,你不能使用另一个查询的主题,直到旧的查询处理。 在PagedList方法中使用&#34; source.Count();&#34;在您使用的第一个和最后一行&#34; source&#34;再次。这不正确。 你有2个解决方案。 1-使用SqlQuery或ExecuteSqlCommand将param发送到PagedList方法和每个新主题 2 - 删除PagedList并将您的分页参数发送到SqlQuery或ExecuteSqlCommand,如下所示:

   const string sqlString =
        @"            
        WITH UserFollowerList
        AS 
        ( 
        SELECT uf.FollowId,ROW_NUMBER() OVER(ORDER BY uf.FollowId ) RowID
        FROM UserFollow uf 
        WHERE uf.UserId = @UserId
        )
        SELECT * FROM UserFollowerList uf
        INNER JOIN [User] u ON uf.FollowId = u.UserId
        WHERE IsDeleted = 0 and RowID BETWEEN (((@PageNumber- 1) *@PageSize)+ 1) AND (@PageNumber * @PageSize))
        "
        ;

答案 4 :(得分:0)

Just encountered this exception even though it was my first query to the database with a single param. And having the Context in a 'using'. When I 'hardcoded' the queryparameter valies into the string it worked correct for some reason. But as soon as I used SqlParameter it gave me the "The SqlParameter is already contained by another SqlParameterCollection"

This didn't work:

context.Database.SqlQuery<int?>(query, new SqlParameter("@TableName", tableName));

This did:

context.Database.SqlQuery<int>(query, new SqlParameter("@TableName", tableName));

The difference being the return type int? vs int. So for anyone reading this. Please also check your return type of the SqlQuery even when you're sure it should work.

答案 5 :(得分:0)

这是旧的,但我遇到了同样的问题,有人在这里想到了解决方案 https://dotnetfiddle.net/GpEd95

基本上,您需要将其拆分为几个步骤才能获得分页查询

//step 1 set the page numbers    

    int pageNumber = 1;
    int pageSize = 2;

//step 2 set your parameters up

        var parm2 = new SqlParameter("param1", "Kevin");
        var parm1  = new SqlParameter("param1", "Kevin");
        var pageParm = new SqlParameter("@p2", (pageNumber - 1) * pageSize);
        var pageSizeParm = new SqlParameter("@p3", pageSize);

 //step 3 split your queries up into search and count

         var sqlString = @"SELECT FT_TBL.*
    FROM EquipmentMaintenances AS FT_TBL
        INNER JOIN FREETEXTTABLE(vw_maintenanceSearch, Search, @param1) AS KEY_TBL ON FT_TBL.EquipmentMaintenanceID = KEY_TBL.[KEY]
        WHERE FT_TBL.Status = 1  
                    ORDER BY RANK DESC,  FT_TBL.EquipmentMaintenanceID DESC OFFSET @p2 ROWS FETCH NEXT @p3 ROWS ONLY";


       var sqlCountString = @"SELECT COUNT(1)
FROM EquipmentMaintenances AS FT_TBL
    INNER JOIN FREETEXTTABLE(vw_maintenanceSearch, Search, @param1) AS KEY_TBL ON FT_TBL.EquipmentMaintenanceID = KEY_TBL.[KEY]
    WHERE FT_TBL.Status = 1  
                ";

//step 4 run your queries c# doesn't like the reusing of parameters so create 2 (e.g Kevin) so your results will run correctly.
            var main = _db.Database.SqlQuery<EquipmentMaintenance>(sqlString, parm1, pageParm, pageSizeParm).ToList();
            var count = _db.Database.SqlQuery<int>(sqlCountString, parm2).FirstOrDefault();

//step 5 created your paged object - I'm using x.pagedlist
            var paged = new StaticPagedList<EquipmentMaintenance>(main, pageNumber, pageSize, count);

显然,您现在将其传递回您的视图或其他功能以进行显示。