The SqlParameter is already contained by another SqlParameterCollection - entity-framework-4

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.

Related

How to perform SUM operation in Entity Framework

I have a table.
create table tblCartItem(
pkCartItemId int primary key identity,
CartId int not null,
ProductId int not null,
Quantity int not null,
Price nvarchar(15)
)
and I want to perform sum opeartion on that like as
Select SUM(Price) from tblCartItem where CartId='107'
and I am trying to following code but its not working
ObjTempCart.CartTotal = (from c in db.tblCartItems where c.CartId == cartId select c.Price).Sum();
Any one help me to do this using Entity Framework.
I am using MVC 4 Razor.
May be You can use lambda Expression
var total=db.tblCartItems.Where(t=>t.CartId == cartId).Sum(i=>i.Price);
its working try this..
use Decimal.Parse to convert price.
ObjTempCart.CartTotal = db.tblCartItems.Where(t=>t.CartId == cartId).Select(i=>Decimal.Parse(i.Price)).Sum();
Finally I have a solution of that but its not exactly from Entity Framework, But its working...
private double CartItemTotalPrice(Int32 CartID)
{
List<string> pricelst = new List<string>();
pricelst = (from c in db.tblCartItems where c.CartId == CartID select c.Price).ToList();
double Total = 0;
if (pricelst != null)
{
for (int i = 0; i < pricelst.Count; i++)
{
Total += Convert.ToDouble(pricelst[i]);
}
}
return Total;
}
Decimal.parse not working, try Convert.toDouble
double total = _context.Projecao
.Where(p => p.Id == idProj)
.Select(i => Convert.ToDouble(i.ValorTotal)).Sum();

How to use PagedList on search results page in MVC?

I am using PagedList on my index view which works fine because it is just a list. So when I click on the next page button, it runs against index and pulls the next set of items. My issue is when trying to use this on my results page after an advanced search. My search works fine in returning results. There are 50+ parameters used in the query and some are include or exclude based on what is checked/selected etc. Here is an example of a possible query:
SQLstatement = string.Format("select * from Cards where {0} and {1} and (({2}) or ({3}))
and CardID In (Select CardID from CardAbilities where {4});", final, finalexcludefrommulti,
finalsplit, finalmulti, finalability);
var CardList = db.Cards.SqlQuery(SQLstatement).ToList();
var pageNumber = page ?? 1;
int pageSize = 5;
ViewBag.OnePageOfCards = pageNumber;
return View(CardList.ToPagedList(pageNumber, pageSize));
This could result in a SQL Query like this:
select * from Cards where maintypeid = 1 and redbluemanacost is null
and redblackmanacost is null and blueblackmanacost is null
and redmanacost is null and bluemanacost is null and blackmanacost is null
and ((whitegreenmanacost > 0 or redgreenmanacost > 0 or greenbluemanacost > 0
or greenblackmanacost > 0 or greenorlifecost > 0 or whitegreenmanacost > 0
or redwhitemanacost > 0 or whitebluemanacost > 0 or whiteblackmanacost > 0
or whiteorlifecost > 0 ) or (greenmanacost > 0 or whitemanacost > 0 ))
and CardID In (Select CardID from CardAbilities
where abilityid = 3 or abilityid = 1007);
Here is part of my view:
#Html.PagedListPager(Model, page => Url.Action("Results", new { page }))
When I use the PagedList, the results still come back, but when I click on next page it tries to rerun the query by going to Url.Action "Results" without any values and crashes. Can I store the results and have paging from that? Is there another paging option that would work better? Thanks for any advice. :)
I got this to work by creating a session that holds the string for the SQLstatement. On my Search/Index controller, I set the Session to null so that a user can start a new search.
Last part of Search Controller:
Session["PageList"] = SQLstatement;
var CardList = db.Cards.SqlQuery(SQLstatement).ToList();
return View(CardList.ToPagedList(pageNumber, pageSize));
New section added to beginning of Search Controller:
var pageNumber = page ?? 1;
int pageSize = 5;
ViewBag.OnePageOfCards = pageNumber;
if (Session["PageList"] != null)
{
string SearchResult = Session["PageList"].ToString();
var ResultList = db.Cards.SqlQuery(SearchResult).ToList();
foreach (var item in ResultList)
{
item.SubType = db.SubTypes.Single(x => x.SubTypeID == item.SubTypeID);
item.MainType = db.MainTypes.Single(x => x.MainTypeID == item.MainTypeID);
item.CardSet = db.CardSets.Single(x => x.CardSetID == item.CardSetID);
item.Rarity = db.Rarities.Single(x => x.RarityID == item.RarityID);
}
ViewBag.OnePageOfCards = pageNumber;
return View(ResultList.ToPagedList(pageNumber, pageSize));
Also pass int? page in the parameters for the Search.
In the Search Index Controller added:
Session["PageList"] = null;

Database.ExecuteSqlCommand returns incorrect rowcount

I'm using context.Database.ExecuteSql to update a table. The update with where clause is executed correctly and the record is updated. However the method returns 2 for rowcount instead of 1. When I execute the update statement in SSMS, the result rowcount returned is 1. Can someone provide insight on this?
string query =
string.Format("update {0} set Description = '{1}', Code = '{2}', LastUpdatedBy = '{3}', LastUpdatedDate = '{4}' where ID = {5};",
tableName,
description,
code,
lastUpdatedBy,
lastUpdatedDate,
ID);
int rowCount = 0;
string message = string.Empty;
using (DBContext context = new DBContext())
{
rowCount = context.Database.ExecuteSqlCommand(TransactionalBehavior.EnsureTransaction, query);
}
return rowCount == 0 ? //this return 2 instead of 1.
new SaveResult(SaveResult.MessageType.Error, string.Format("There was an error updating a record in the {0} table.", tableName), "Index") :
new SaveResult(SaveResult.MessageType.Success, string.Format("The update of {0} was successful.", tableName), "Index");
This returns rowcount = 1 in SSMS:
update zAddressTypes
set Description = 'Current', Code = '101122', LastUpdatedBy = 'user', LastUpdatedDate = '10/20/2014 12:17:26 PM'
where ID = 1;
DECLARE #RowCount INTEGER = ##ROWCOUNT;
select #RowCount;
The rowcount is being returned separately. What you are seeing here is the exit status of the query.
ExecuteSqlCommand return value is for the status of query not for row count. You may want to look into using a datareader or something similar to return the rowcount.
It is the way the datacontext works, see this link:
Entity Framework: Database.ExecuteSqlCommand Method
Apparently the command is updating two records.
Do you have a trigger on your table? I confirmed this behavior can be caused by a trigger as the rows affected by the trigger are added to the row count affected by your SQL command. I commonly check for a 0 or >0 return value to know if anything was affected. You could also return an output variable if you're calling a stored procedure.

Create a custom list of Orders in NopCommerce

I'm trying to create a list of orders in a custom Controller in a NopCommerce/MVC application and i want the list to be sorted by creationDate and contain total orders for that date and convert these values to string format.
The thing is i don't want an ActionResult displaying a grid in the view like in Admin/Orders. All i want is a List of all paid orders between model.StartDate and model.EndDate that contains two parameters "CreationDateUtc" and TotalOrders". i simply just need a list containing the data of orders sorted by creationdate.
The if i choose StartDate 2014-03-29 and EndDate 2014-04-02 the output i want would look something like this:
List OrdersTotalList with parameters CreationDateUtc and TotalOrders
CreationDateUtc "2014-03-29"
TotalOrders "562"
CreationDateUtc "2014-03-30"
TotalOrders "485"
CreationDateUtc "2014-03-31"
TotalOrders "733"
CreationDateUtc "2014-04-01"
TotalOrders "729"
CreationDateUtc "2014-04-02"
TotalOrders "681
"
I'm trying to access the data by an implementations of OrderList from OrderController in my CustomController. Problem is this method always returns 10 objects when infact the total number of orders within this timespace is 58. When debugging Total = orders.TotalCount are actually showing 58 orders as one int value). Also a gridmodel is used here but i really don't need a gridmodel, i just need the data from the database:
public List OrderList(GridCommand command, OrderListModel model, OrderModel Omodel)
{
DateTime S = new DateTime(2014, 3, 29); //-- Dates for testing
DateTime E = new DateTime(2014, 4, 02);
model.StartDate = S;
model.EndDate = E;
DateTime? startDateValue = (model.StartDate == null) ? null
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone);
DateTime? endDateValue = (model.EndDate == null) ? null
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1);
OrderStatus? orderStatus = model.OrderStatusId > 0 ? (OrderStatus?)(model.OrderStatusId) : null;
PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null;
ShippingStatus? shippingStatus = model.ShippingStatusId > 0 ? (ShippingStatus?)(model.ShippingStatusId) : null;
//load orders
var orders = _orderService.SearchOrders(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid, command.Page - 1, command.PageSize);
var gridModel = new GridModel<OrderModel>
{
Data = orders.Select(x =>
{
var customerCurrency = _currencyService.GetCurrencyByCode(x.CustomerCurrencyCode);
var totalInCustomerCurrency = _currencyService.ConvertCurrency(x.OrderTotal, x.CurrencyRate);
return new OrderModel()
{
Id = x.Id,
OrderTotal = _priceFormatter.FormatPrice(totalInCustomerCurrency, true, customerCurrency),
OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext),
PaymentStatus = x.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext),
ShippingStatus = x.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext),
CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc)
};
}),
Total = orders.TotalCount <-- Returns all orders (58) but as an integer
};
var reportSummary = _orderReportService.GetOrderAverageReportLine
(orderStatus, paymentStatus, shippingStatus, startDateValue, endDateValue, model.CustomerEmail);
var profit = _orderReportService.ProfitReport
(orderStatus, paymentStatus, shippingStatus, startDateValue, endDateValue, model.CustomerEmail);
var aggregator = new OrderModel()
{
aggregatorprofit = _priceFormatter.FormatPrice(profit, true, false),
aggregatortax = _priceFormatter.FormatPrice(reportSummary.SumTax, true, false),
aggregatortotal = _priceFormatter.FormatPrice(reportSummary.SumOrders, true, false)
//aggregatordates =
};
List<Order> TotalProductsSold = new List<Order>();
foreach (var o in orders)
{
TotalProductsSold.Add(o);
}
return TotalProductsSold.ToList(); //<-- returns 10 orders containing all order info
}
If i understand correct in order to archive this i have to first search through orders and if their PaymentStatus is Paid. Then create a List in the Method from above. A foreach loop could iterate through orders and add orders to the List, all though i need to specify i only want CreationDate and TotalOrders for that date as parameters in the List.
I know this isn't right but i emagine something similar. The thing is i need a list of order objects and not one object with one value:
List<OrderModel> OrdersTotalList = new List<OrderModel>();
foreach (var o in orders)
{
OrderModel OM = new OrderModel(OM.OrderTotal, OM.CreatedOn);
OrdersTotalList.Add(OM);
}
return OrdersTotalList; //--
Am i completely of or is this the right aproach? I was hoping someone more familiar with NopCommerce knows more about this.
Sorry for all the text
Thank you
Solved.
In order to get a full list of orders you can create a new constructor in IOrderService/OrderService that is of type List instead of IPagedList. The method used for searching orders are called "SearchOrders" and is of type IPagedList. IPagedList contains the property PageSize wich results in only 10 orders.
You can create a new method with same implementation as SearchOrders and change IPagedList to List, remove "int pageIndex" and "int pageSize".
Then use:
_orderService.YourNewConstructor(DateTime? startTime, DateTime? endTime,
OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss, string billingEmail,
string orderGuid)
{
some code...
}
This will give you access to all orders.

Insert into multiple database tables using Linq, ASP.NET MVC

I have a rather simple scenario where I have two tables in which I want to add data. They are managed with primary key/foreign key. I want to add new data into TABLE A and then retrieve the Id and insert into TABLE B.
I can certainly do it with a stored procedure, but I'm looking at trying to do it using Linq.
What is the best approach ?
I can certainly get the ID and do two separate inserts but that doesn't certainly seem to be a very good way of doing things.
db.Table.InsertOnSubmit(dbObject);
db.SubmitChanges();
Int32 id = dbOject.Id;
//Rest of the code
Any way to elegantly do this?
Do you have the relationship defined between the 2 tables in the object relational designed? If so, you can have linq take care of assigning the ID property of the second table automatically.
Example...
Table A – Order
OrderId
OrderDate
Table B – Order Item
OrderItemId
OrderId
ItemId
Code (Using LINQ-to-SQL):
Order order = new Order();
Order.OrderDate = DateTime.Now();
dataContext.InsertOnSubmit(order);
OrderItem item1 = new OrderItem();
Item1.ItemId = 123;
//Note: We set the Order property, which is an Order object
// We do not set the OrderId property
// LINQ will know to use the Id that is assigned from the order above
Item1.Order = order;
dataContext.InsertOnSubmit(item1);
dataContext.SubmitChanges();
hi i insert data into three table using this code
Product_Table AddProducttbl = new Product_Table();
Product_Company Companytbl = new Product_Company();
Product_Category Categorytbl = new Product_Category();
// genrate product id's
long Productid = (from p in Accountdc.Product_Tables
select p.Product_ID ).FirstOrDefault();
if (Productid == 0)
Productid++;
else
Productid = (from lng in Accountdc.Product_Tables
select lng.Product_ID ).Max() + 1;
try
{
AddProducttbl.Product_ID = Productid;
AddProducttbl.Product_Name = Request.Form["ProductName"];
AddProducttbl.Reorder_Label = Request.Form["ReorderLevel"];
AddProducttbl.Unit = Convert.ToDecimal(Request.Form["Unit"]);
AddProducttbl.Selling_Price = Convert.ToDecimal(Request.Form["Selling_Price"]);
AddProducttbl.MRP = Convert.ToDecimal(Request.Form["MRP"]);
// Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl );
// genrate category id's
long Companyid = (from c in Accountdc.Product_Companies
select c.Product_Company_ID).FirstOrDefault();
if (Companyid == 0)
Companyid++;
else
Companyid = (from Ct in Accountdc.Product_Companies
select Ct.Product_Company_ID).Max() + 1;
Companytbl.Product_Company_ID = Companyid;
Companytbl.Product_Company_Name = Request.Form["Company"];
AddProducttbl.Product_Company = Companytbl;
//Genrate Category id's
long Categoryid = (from ct in Accountdc.Product_Categories
select ct.Product_Category_ID).FirstOrDefault();
if (Categoryid == 0)
Categoryid++;
else
Categoryid = (from Ct in Accountdc.Product_Categories
select Ct.Product_Category_ID).Max() + 1;
Categorytbl.Product_Category_ID = Categoryid;
Categorytbl.Product_Category_Name = Request.Form["Category"];
AddProducttbl.Product_Category = Categorytbl;
Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl);
Accountdc.SubmitChanges();
}
catch
{
ViewData["submit Error"] = "No Product Submit";
}

Resources