我使用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 }
我该怎么做才能解决我遇到的错误?
答案 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);
显然,您现在将其传递回您的视图或其他功能以进行显示。