質問

I'm using EF DbContext SqlQuery to get a list of paged objects using PagedList (https://github.com/TroyGoode/PagedList) and I'm getting the following error:

"The SqlParameter is already contained by another SqlParameterCollection"

Here's my repository code:

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;

But when I call the ToList extension on the SqlQuery statement it works fine:

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

PagedList code:

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();
    }

I've already the solution below without any success:

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

What can I do to fix the error I'm experiencing?

役に立ちましたか?

解決

FYI I just saw this exact same error message when using an EF 5 DbContext to call context.ExecuteQuery<my_type>(...); with an array of SqlParameters, where my_type had a string but the SQL statement was returning an int for one of the parameters.

The error was really in the return mapping, but it said the SqlParameter was to blame, which threw me off for a little while.

他のヒント

When using a generic call to SqlQuery such as db.Database.SqlQuery you must iterate to the last record of the returned Set in order for the result set and associated parameters to be released. PagedList uses source.Take(pageSize).ToList() which will not read to the end of the source set. You could work around this by doing something like foreach(User x in userList) prior to returning the result.

I tried the following solution from Diego Vega at http://blogs.msdn.com/b/diego/archive/2012/01/10/how-to-execute-stored-procedures-sqlquery-in-the-dbcontext-api.aspx and it worked for me:

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

When you are using parameters on (SqlQuery or ExecuteSqlCommand) you can't use theme by another query until old query dispose. in PagedList method you use "source.Count();" at first and the end line you are using "source" again. that's not correct. you have 2 solution. 1- send param to PagedList Method and new theme for each using SqlQuery or ExecuteSqlCommand 2-remove PagedList and send your paging param to SqlQuery or ExecuteSqlCommand like this :

   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))
        "
        ;

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.

This is old, but I ran into the same problem and someone has thought of the solution here https://dotnetfiddle.net/GpEd95

Basically you need to split this up into a few steps in order to get your paged query

//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);

Obviously your now passing this back to your view or other function for display.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top