Error while adding multiple items to an entity - asp.net-mvc

for (int i = 0; i < skus.Count; i++)
{
sku item = new sku();
item = skus[i];
sku sku = CompanyDbContext.skus.Where(s => s.item_no == item.item_no).FirstOrDefault();
if (sku == null) // ok to insert [no duplicate item numbers]
{
CompanyDbContext.skus.Add(item);
}
}
CompanyDbContext.SaveChanges();
I'm getting
collection was modified enumeration operation may not execute
error. How can I fix this ?

As mentioned in the comments, this happens because you are modifying the collection which you are looping through as you're performing your work.
One option you have is to create a temporary collection and add your sku items to that, and finally add the contents of the temporary List<sku> to your CompanyDbContext
// Create a new temporary list
List<sku> tempSkus = new List<sku>();
for (int i = 0; i < skus.Count; i++)
{
// Let's assign item to skus[i] immediately, we don't need a new instance here when we're later re-pointing to an existing instance
sku item = skus[i];
// Use LINQ Any function to determine whether there are any existing SKU's already
bool existingSku = CompanyDbContext.skus.Any(s => s.item_no == item.item_no);
// There are no duplicates, let's add this sku item to our temporary List
if(!existingSku)
{
tempSkus.Add(item);
}
}
// Add the Range of tempSkus List to the CompanyDbContext
CompanyDbContext.skus.AddRange(tempSkus);
CompanyDbContext.SaveChanges();
Or if you prefer LINQ
// Create a new temporary list
List<sku> tempSkus = skus.Where(p => CompanyDbContext.skus.Any(s => s.item_no != p.item_no)).ToList();
// Add the Range of tempSkus List to the CompanyDbContext
CompanyDbContext.skus.AddRange(tempSkus);
CompanyDbContext.SaveChanges();

The problem is that you are modify the same thing that you are iterating. As best practice you should update your method something like this:
//get search predicat from List<sku> skus
var item_nos = skus.Select(s=>s.item_no).ToList();
//items already in repo
var addedItems = CompanyDbContext.skus.Where(s => item_nos.Contains(s.item_no)).ToList();
var newItems = skus.Except(addedItems).ToList();
foreach(var sku in newItems){
CompanyDbContext.skus.Add(item);
}
CompanyDbContext.SaveChanges();

Related

More efficient way to get strings out of a Dart list of classes

Just looking for a more efficient way to do this in Dart:
List<String> tagStrings = List();
List<TagCategory> categories = List();
source.forEach(
(content) {
if (content.tagCategories != null) {
categories.addAll(content.tagCategories);
}
},
);
categories = categories.toSet().toList(); // remove duplicates
categories.forEach(
(element) {
List<Tag> tags = element.tags;
tags.forEach(
(tag) {
tagStrings.add(tag.label);
},
);
},
);
tagStrings = tagStrings.toSet().toList();
I have a list of Trail objects with a list of TagCategory objects that themselves have a list of Tag objects with a String property called label.
I am trying to strip out all these tags for use in a filter, and I need duplicates to be removed hence the hack to convert to a set and then back into a list which I can sort.
What is the most efficient way to do this?
Converting to a set to avoid duplicates is fine.
I'd write it as a literal:
Try:
var tags = [...{for (var tag in {for (var content in source) ...?content.tagCategories})
tag.label}];
You can then worry about whether you really need to remove duplicates in tag categories if you are removing the duplicates in the labels afterwards anyway.
If performance is the only goal, then I'd probably do something slightly more imperative, like:
var set = <String>{}
for (var content in source) {
var categories = content.tagCategories;
if (categories != null) {
for (var category in categories) set.add(category.label);
}
}
var tagStrings = set.toList();

ASP.NET MVC 5, Storing list values in Session

I am trying to store list of products in List<> which I have stored in session, but when I add second product it only shows first in my View page.
..............
List<ShoppingCartItem> ShoppingCartItems = new List<ShoppingCartItem>
{
new ShoppingCartItem() {Product = product.Name, Attributes = atts, Options = opts, Price = producttotalprice, Quantity = 1}
};
if (Session["Cart"] == null)
{
Session["Cart"] = ShoppingCartItems;
}
return View(Session["Cart"]);
}
Anybody can help me please to retrieve all products I have stored.
You're creating a new List<ShoppingCartItem> every time and only ever putting one element in that list. It sounds like you want to first check if there's already a list in the session. And, if so, add the new element to that list. Something like this:
List<ShoppingCartItem> shoppingCartItems;
if (Session["Cart"] != null)
{
shoppingCartItems = (List<ShoppingCartItem>)Session["Cart"];
}
else
{
shoppingCartItems = new List<ShoppingCartItem>();
}
shoppingCartItems.Add(new ShoppingCartItem() {Product = product.Name, Attributes = atts, Options = opts, Price = producttotalprice, Quantity = 1});
Session["Cart"] = shoppingCartItems;
return View(shoppingCartItems);
If that is the "add" code, you're not actually amending the list. You're declaring an entirely new ShoppingCartItems list which contains the new product.
It works for the first product because this returns true:
if (Session["Cart"] == null)
The second time around this is false, and nothing happens. What you want to do is:
1) Retrieve the session cart which is a 'List' (if it is null, then initialise a new one.
2) Create a new ShoppingCartItem from the product which has been passed to the controller. Add that product to the cart.

iterate through array and compare to entity object

I'm trying to get the various items in a one to many relationship of database objects. So I have the entity framework create my locations object and one column in the table has a comma separated list of services available at a location. I use:
var data = pubDB.Locations.Include("Branch_Ameneties");
in the model to get the relationsihp between a the two tables. Then in the view I am trying to iterate through the features in an array and get the associated Branch Amenities:
#foreach (var Location in Model.LocationListings())
{
#if (Location.Features != null)
{
string[] featureset = Location.Features.Split(',');
foreach (var item in featureset)
{
var feature = Location.Branch_Ameneties.Amenity.Where(x => Location.Branch_Ameneties.FID = Convert.ToInt32(item);
#feature
}
}
And I can't seem to get the array to associate with the reference table of amentiites.
instead of using the where clause, try using:
var feature = Location.Branch_Ameneties.Amenity.Single(x => Location.Branch_Ameneties.FID == Convert.ToInt32(item));
Also, you had "..FID = Convert.ToInt32(item)" instead of "..FID == Convert..."

load navigation properties with filter for Entity Framework 4.3

Few days back I put a question regarding mapping two classes Message and MessageStatusHistory using EF. The mapping is going fine but I am facing some problems with the navigation property StatusHistory in class Message that relates it to MessageStatusHistory objects. I am loading the messages for one user only and want to the statuses pertaining to that user only. Like I would want to show if the user has marked message as read/not-read and when. If I use default loading mechanism like following it loads all the history related to the message irrespective of the user:
IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);
To filter history for one user only I tried following trick:
IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
where m.MessageIdentifier == msgIdentifier
select new Message
{
MessageIdentifier = m.MessageIdentifier,
/*OTHER PROPERTIES*/
StatusHistory = m.StatusHistory
.Where(x => x.UserId == userId).ToList()
};
return q.ToList();//THROWING ERROR ON THIS LINE
I am getting the error:
The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ
to Entities query.
I have tried by commenting StatusHistory = m.StatusHistory.Where(x => x.UserId == userId).ToList() also but it has not helped.
Please help me in getting Messages with filtered StatusHistory.
EDIT:- above is resolved with this code:
var q = from m in _repository.DBSet.Include("Histories")
where m.MessageIdentifier == id
select new {
m.Id,/*OTHER PROPERTIES*/
Histories = m.Histories.Where(x =>
x.SenderId == userId).ToList()
};
var lst = q.ToList();
return lst.Select(m => new Message{
Id = m.Id, MessageIdentifier = m.MessageIdentifier,
MessageText = m.MessageText, Replies = m.Replies,
ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId =
m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
}).ToList();
But if I try to include replies to the message with:
from m in _repository.DBSet.Include("Replies").Include("Histories")
I am getting error on converting query to List with q.ToList() for Histories = m.Histories.Where(x=> x.SenderId == userId).ToList().
About your EDIT part: You cannot use ToList() in a projection, just leave it an IEnumerable<T> and convert to a List<T> when you construct the Message. You also don't need to create two list objects, you can switch from the LINQ to Entities query to LINQ to Objects (the second Select) by using AsEnumerable():
var list = (from m in _repository.DBSet
where m.MessageIdentifier == id
select new {
// ...
Histories = m.Histories.Where(x => x.SenderId == userId)
})
.AsEnumerable() // database query is executed here
.Select(m => new Message {
// ...
Histories = m.Histories.ToList(),
// ...
}).ToList();
return list;
Be aware that Include has no effect when you use a projection with select. You need to make the properties that you want to include part of the projection - as you already did with select new { Histories.....

How do i select a record in a grouped smartgwt listgrid?

I have site with a listgrid and a openlayers map with points. When i cklick on one of these, the application shall scroll and mark this record. This works with a standard listgrid, but with a grouped listgrid it does not work.
lg = new ListGrid();
lg.setWidth(330);
lg.setDataSource(ds1);
lg.setAutoFetchData(true);
lg.setSortField("KU_NAME");
lg.setGroupStartOpen(GroupStartOpen.ALL);
lg.setGroupByField("KU_NAME");
lg.setShowFilterEditor(true);
kuName = new ListGridField("KU_NAME", "Künstler Name",150);
// Standorte
ListGridField stdOrt = new ListGridField("STDORT_NR","Standort Nr.");
ListGridField oid = new ListGridField("OID","OID.");
lg.setFields(stdOrt,kuName,oid);
and the select:
String stdortOID = stdOrtOIDjso.toString();
ListGridRecord[] records = lg.getRecords();
int i;
for (i = 0; i < records.length; i++) {
if (records[i].getAttribute("OID").equalsIgnoreCase(stdortOID)){
break;
}
}
lg.deselectAllRecords();
lg.selectRecord(i);
lg.scrollToRow(lg.getRecordIndex(record));
the reason is that in the record is only the value of the group name and the other attributs are unavailable.
When grouping is enabled, all data are "transformed" into tree and listgrid itself contains data for groups so you have to look for your record in this tree. Replace last 3 lines with (modified) Vittorio Paternostro suggestion:
Tree tree = lg.getGroupTree();
if (tree != null) {
TreeNode node = tree.find("OID", stdortOID);
if (node != null) {
lg.selectSingleRecord(node);
lg.scrollToRow(getRecordIndex(node));
lg.markForRedraw();
}
}
Note: Instead of deselectAllRecords + selectRecord use simplified selectSingleRecord.
I had the same need and the following works fine for me. You can use getGroupTree() and search the desired property in it (column value) without worrying about grouping. Make sure you search for unique values (i.e. a unique key) to identify a precise node.
Tree tree = getGroupTree();
if (tree != null) {
TreeNode node = tree.find("property", "value");
if (node != null) {
selectSingleRecord(node);
scrollToRow(getRecordIndex(node));
markForRedraw();
}
}

Resources