In MVC, pass complex query and view model to session? - mysql

I have a view model:
public class UserCollectionView
{
public CardCollection CardCollections { get; set; }
public Card Cards { get; set; }
}
I have a List View Controller:
public ActionResult ViewCollection(int? page)
{
var userid = (int)WebSecurity.CurrentUserId;
var pageNumber = page ?? 1;
int pageSize = 5;
ViewBag.OnePageOfCards = pageNumber;
if (Session["CardCollection"] != null)
{
var paging = Session["CardCollection"].ToString.();
return View(paging.ToPagedList(pageNumber, pageSize));
}
var viewModel = from c in db.Cards
join j in db.CardCollections on c.CardID equals j.CardID
where (j.NumberofCopies > 0) && (j.UserID == userid)
orderby c.Title
select new UserCollectionView { Cards = c, CardCollections = j };
Session["CardCollection"] = viewModel;
return View(viewModel.ToPagedList(pageNumber, pageSize));
I am trying to use the PagedList to add paging to the results. I have been able to do this when I am not using a query that returns data from 2 databases in a single view. As shown here
My end result looks something like this:
Cards.SeveralColumns CardCollections.ColumnA CardCollections.ColumnB
Row 1 Data from Cards Table A from CardCollections B from CardCollections
Row 2 Data from Cards Table A from CardCollections B from CardCollections
Row 3 Data from Cards Table A from CardCollections B from CardCollections
And so on... I get an error
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I have tried variations of SQL statements but can't get it to fit with my view model. In SQL Management Studio this brings back the correct results
Select * from Cards Inner Join CardCollections On Cards.CardID = CardCollections.CardID where CardCollections.UserID = 1 and CardCollections.NumberofCopies > 0;
I need a way to pass the query in session so the paging will operate correctly. Any advice is appreciated. :)

Short answer is, you can't. The model needs to be a snapshot of the content and therefore you can't pass an open query across the boundary (either as a hand-off to a session or to the client directly).
What you're seeing is the disposal of the context beyond it's initial use (where you assemble var viewmodel).
With that said, you can cache the results (to save overhead) if querying the data is an expensive operation. Basically, you'd store the entire collection (or at least a large subset of the collection) in the session/memorycache (which can then be manipulated into a paged list). Something to the effect of:
public ActionResult ViewCollection(int? page)
{
var userId = (int) WebSecurity.CurrentUserId;
var pageNumber = page ?? 1;
var pageSize = 5;
ViewBag.OnePageOfCards = pageNumber;
var cacheKey = String.Format("ViewCollection[{0}]", userId);
var entities = GetOrCreateCacheItem<IEnumerable<UserCollectionView>>(cacheKey, () => {
var query = (from c in db.Cards
join j in db.CardCollections on c.CardID equals j.CardID
where (j.NumberofCopies > 0) && (j.UserID == userid)
orderby c.Title
select new UserCollectionView { Cards = c, CardCollections = j }
)
.ToList(); // Force fetch from Db so we can cache
});
return View(entities.ToPagedList(pageNumber, pageSize));
}
// To give an example of a cache provider; Feel free to change this,
// abstract it out, etc.
private T GetOrCreateCacheItem<T>(string cacheKey, Func<T> getItem)
{
T cacheItem = MemoryCache.Default.Get(cacheKey) as T;
if (cacheItem == null)
{
cacheItem = getItem();
var cacheExpiry = DateTime.Now.AddMinutes(5);
MemoryCache.Default.Add(cacheKey, cacheItem, cacheExpiry);
}
return cacheItem;
}

It turns out that I didn't need to pass the query at all. If I let it run through it works fine without the session. I am not really sure why this works but my search query has to be passed. Maybe it is because I am using a viewmodel to perform the query. I will experiment and post if I find anything. Currently the working code is:
public ActionResult ViewCollection(int? page)
{
var userid = (int)WebSecurity.CurrentUserId;
var pageNumber = page ?? 1;
int pageSize = 5;
ViewBag.OnePageOfCards = pageNumber;
ViewBag.Rarity_ID = new SelectList(db.Rarities, "RarityID", "Title");
ViewBag.MainType_ID = new SelectList(db.MainTypes, "MainTypeID", "Title");
ViewBag.CardSet_ID = new SelectList(db.CardSets, "CardSetID", "Title");
ViewBag.SubType_ID = new SelectList(db.SubTypes, "SubTypeID", "Title");
var viewModel = from c in db.Cards
join j in db.CardCollections on c.CardID equals j.CardID
where (j.NumberofCopies > 0) && (j.UserID == userid)
orderby c.Title
select new UserCollectionView { Cards = c, CardCollections = j };
return View(viewModel.ToPagedList(pageNumber, pageSize));

Related

Report don't display any data

I'm working on D365FO. I did create a report added a query to dataset that is based on a tmp table.
Now when I try to generate the report I get just the precisiondesign. No data is shown in it. How can I fix this ?
I think this is problem is somewhere outside of my code because I tried to generate a already created report and had the same problem.
[SrsReportParameterAttribute(classStr(ProductionStatusContract))]
class ProductionStatusDP extends SrsReportDataProviderBase
{
ProductionStatusTmp ProductionStatusTmp;
ProdTable prodtable;
SalesTable salestable;
InventDim inventdim;
SalesLine salesline;
public void processReport()
{
ProductionStatusContract contract = this.parmDataContract() as
ProductionStatusContract;
date FromDate;
date ToDate;
boolean DateBetween = false;
if(contract.parmToDate() && contract.parmFromDate())
{
ToDate = contract.parmToDate();
FromDate = contract.parmFromDate();
DateBetween = true;
}
super();
delete_from ProductionStatusTmp;
ProductionStatusTmp.clear();
while select prodtable where prodtable.CollectRefLevel == 0
join inventdim where prodtable.InventDimId == inventdim.inventDimId
join salesline where prodtable.InventRefType == salesline.InventRefType
&& prodtable.InventRefId == salesline.SalesId
&& prodtable.InventRefTransId == salesline.InventTransId
&& prodtable.InventRefType == inventreftype::Sales
{
ProductionStatusTmp.clear();
Info(strFmt("%1", prodtable.ProdId));
ProductionStatusTmp.AcceptedDate = prodtable.CreatedDateTime;
ProductionStatusTmp.ProdWeek = wkOfYr(prodtable.CreatedDateTime) + year(prodtable.CreatedDateTime);
ProductionStatusTmp.ExternalNum = salesline.ExternalItemId;
ProductionStatusTmp.Progress = ((prodtable.qtycalc * 100) / prodtable.QtySched);
ProductionStatusTmp.Quantity = prodtable.QtyCalc;
ProductionStatusTmp.AcceptedBy = prodtable.CreatedBy;
ProductionStatusTmp.ProdItemId = InventDim.InventLocationId;
ProductionStatusTmp.Ware = prodtable.Name;
ProductionStatusTmp.ProductionStatus = prodtable.ProdStatus;
ProductionStatusTmp.Produced = prodtable.QtySched;
ProductionStatusTmp.insert();
}
}
[SrsReportDataSetAttribute(tableStr(ProductionStatusTmp))]
public ProductionStatusTmp getProductionStatusTmp()
{
select ProductionStatusTmp;
return ProductionStatusTmp;
}
}
You will have to verify that your report does indeed display the data you provide.
You can do this by providing fixed static data in your data provider to see if shows up in the SSRS report preview.
See this video for an example to see how.

insert selected value from drop down by razor mvc

hi, I had aproject and one of my task as to insert selected value from
drop down to DB field by razor mvc. I did my code but no values inserted ,Also the DDL have items from DB well . my project with razor mvc4.
public ActionResult Create()
{
var data = db.Categories.ToList().Distinct();
foreach (var t in data)
{
s.Text = t.Name;
s.Value = t.Cat_ID.ToString();
items.Add(s);
}
ViewBag.Parent = items;
return View();
}
[HttpPost]
public ActionResult Create(Category category, IEnumerable<HttpPostedFileBase> files)
{
if (Request.Files.Count > 0)
{
var uploadedFile = Request.Files[0];
var fileSavePath = "";
var fileName = "";
fileName = Path.GetFileName(uploadedFile.FileName);
fileSavePath = Server.MapPath("~/App_Data/Uploads/" + fileName);
uploadedFile.SaveAs(fileSavePath);
category.Path = "~/App_Data/Uploads/" + fileName;
}
var data = db.Categories.ToList().Distinct();
List<SelectListItem> items = new List<SelectListItem>();
foreach (var t in data)
{
SelectListItem s = new SelectListItem();
s.Text = t.Name;
s.Value = t.Cat_ID.ToString();
items.Add(s);
if (s.Selected)
{ category.Parent_ID = int.Parse(s.Value); }
}
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Index");
}
Hi Your code should be something like this. I am assuming that you have model with certain structure. If belo code does not give you a clue then please. Tell how your view and model is and what is your requirement.
Hope this helps.
[HttpPost]
public ActionResult Create(Category category, IEnumerable<HttpPostedFileBase> files)
{
if (Request.Files.Count > 0)
{
var uploadedFile = Request.Files[0];
var fileSavePath = "";
var fileName = "";
fileName = Path.GetFileName(uploadedFile.FileName);
fileSavePath = Server.MapPath("~/App_Data/Uploads/" + fileName);
uploadedFile.SaveAs(fileSavePath);
category.Path = "~/App_Data/Uploads/" + fileName;
}
var data = db.Categories.ToList().Distinct();
//I assume that you need to find the category from db.Caegories which user has selected on the UI and submited the form.
//I assume the parameter category is the one which you want to find from DB.
//category is your model has Parent_Id property which is bound to UI control (ie. dropdown)
var categoryToSave = (from c in data
where c.Cat_ID == category.Parent_ID
select c).firstOrDefault();
if(categoryToSave!=null)
{
//I believe here you want to save this category to some other table.
//Now you have got the category tht user has selected on UI.
//Write the further logic here.....
db.SaveChanges();
}
return RedirectToAction("Index");
}
Regards, Mahesh
you are creating the fresh selectListItem s here in the same loop. You will get seleced == true for any of the item.
May be item, that user has selected on UI (before post) exist in category param if it is your model that is bound to desired dropdown.
I suspect it is a logical error.
Regards, Mahesh

What's the risk of multiple SubmitChanges?

Is there a risk with the code below that if two people submit at the same time the wrong s.saleID will be retrieved?
protected void submitSale(int paymentTypeID)
{
tadbDataContext tadb = new tadbDataContext();
ta_sale s = new ta_sale();
decimal total = decimal.Parse(lblTotal.Value);
s.paymentTypeID = paymentTypeID;
s.time = DateTime.Now;
s.totalSale = total;
tadb.ta_sales.InsertOnSubmit(s);
tadb.SubmitChanges();
char[] drinksSeparator = new char[] {'|'};
char[] rowSeparator = new char[] { ':' };
string drinkString = lblSummaryQty.Value.Substring(0, lblSummaryQty.Value.Length - 1);
string[] arrDrinks = drinkString.Split(drinksSeparator);
foreach (string row in arrDrinks)
{
string[] arrDrink = row.Split(rowSeparator);
int rowID = Convert.ToInt16(arrDrink[0]);
int rowQty = Convert.ToInt16(arrDrink[1]);
ta_saleDetail sd = new ta_saleDetail();
sd.drinkID = rowID;
sd.quantity = rowQty;
sd.saleID = s.saleID;
tadb.ta_saleDetails.InsertOnSubmit(sd);
}
tadb.SubmitChanges();
}
}
If so, what should I do to make sure it is atomic? (I think it should be OK, but want to double check!)
To be shure that it's ok just write a test that call submitSale 2 or even more times and make it to submit changes almost at the same time. If test will fail, use lock statement, but be carefull, it can cause deadlocks. After you change submitSale just test it again with high load (a lot of simultaneous calls). And so on until you pass the test.

JSON, MVC2 Disordered data in even cell cointainers

I got into troubles trying to feed the jqgrid with required information. I did everything as suppose to be done, but apparently there is an issue.
Every second cell is order differently, so first row is ok:
[{"id":"AA1","cell":["AA1","AD + DNS + WINS","dev"]},
but the next one is ordered like below:
{"id":"AA2","cell":["dev","AD + DNS + WINS","AA2"]}
when 3rd is ok, and 4th is disordered and so on.
Code which is responsible for this process is below:
var jsonData = new
{
total = totalPages,
page = page,
records = totalRecords,
rows = (
from l in lst
select new
{
id = l.HostName,
cell = new List<string> {
l.HostName, l.Description, l.Type
}
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
Why is like that? I was trying use instead of List the String[], but Linq doesn't like that and pop up error, which suggest List instead of string array.
Is there any way to sustain desired order?
What was your code to use string[]? I got this working without any trouble:
var jsonData = new
{
total = totalPages,
page = page,
records = totalRecords,
rows = (from l in lst
select new
{
id = l.HostName,
cell = new string[] {
l.HostName,
l.Description,
l.Type
}
}).ToArray()
};
You can find similar samples here (but remember that in general they are very old and I would suggest looking at more up to date ones here or here).

Linq-2-Sql code: Does this scale?

I'm just starting to use linq to sql. I'm hoping that someone can verify that linq-2-sql has deferred execution until the foreach loop is executed. Over all, can someone tell me if this code scales. It's a simple get method with a few search parameters. Thanks!
Code:
public static IList<Content> GetContent(int contentTypeID, int feedID, DateTime? date, string text)
{
List<Content> contentList = new List<Content>();
using (DataContext db = new DataContext())
{
var contentTypes = db.ytv_ContentTypes.Where(p => contentTypeID == -1 || p.ContentTypeID == contentTypeID);
var feeds = db.ytv_Feeds.Where(p => p.FeedID == -1 || p.FeedID == feedID);
var targetFeeds = from f in feeds
join c in contentTypes on f.ContentTypeID equals c.ContentTypeID
select new { FeedID = f.FeedID, ContentType = f.ContentTypeID };
var content = from t in targetFeeds
join c in db.ytv_Contents on t.FeedID equals c.FeedID
select new { Content = c, ContentTypeID = t.ContentType };
if (String.IsNullOrEmpty(text))
{
content = content.Where(p => p.Content.Name.Contains(text) || p.Content.Description.Contains(text));
}
if (date != null)
{
DateTime dateTemp = Convert.ToDateTime(date);
content = content.Where(p => p.Content.StartDate <= dateTemp && p.Content.EndDate >= dateTemp);
}
//Execution has been defered to this point, correct?
foreach (var c in content)
{
Content item = new Content()
{
ContentID = c.Content.ContentID,
Name = c.Content.Name,
Description = c.Content.Description,
StartDate = c.Content.StartDate,
EndDate = c.Content.EndDate,
ContentTypeID = c.ContentTypeID,
FeedID = c.Content.FeedID,
PreviewHtml = c.Content.PreviewHTML,
SerializedCustomXMLProperties = c.Content.CustomProperties
};
contentList.Add(item);
}
}
//TODO
return contentList;
}
Depends on what you mean with 'scales'. DB side this code has the potential of causing trouble if you are dealing with large tables; SQL Server's optimizer is really poor at handling the "or" operator in where clause predicates and tend to fall back to table scans if there are multiple of them. I'd go for a couple of .Union calls instead to avoid the possibility that SQL falls back to table scans just because of the ||'s.
If you can share more details about the underlying tables and the data in them, it will be easier to give a more detailed answer...