Issue with removing records in EF - c#

I have a list of organizations attached to the users that need to be removed and a new set added. I am using entity framework
var user = db.Users.Find(model.Id);
foreach (var item in user.Organizations)
{
user.Organizations.Remove(item);
}
var userOrgs = db.Organizations.Where(o => model.Organizations.Contains(o.ID)).ToList();
foreach (var item in userOrgs)
{
user.Organizations.Add(item);
}
db.SaveChanges();
I end up getting an exception {"Collection was modified; enumeration operation may not execute."} when i try to remove the second item. Is there an alternate approach?

Try to use ToList in your first foreach:
var user = db.Users.Find(model.Id);
foreach (var item in user.Organizations.ToList())
{
user.Organizations.Remove(item);
}

Related

Insert Multiple Rows to Database LINQ

I have a foreach loop that iterates through a list of type List<NewItem>, creates a new instance of NewItem, sets its properties, then Add()s the item to the context to be inserted upon the execution of SaveChanges():
foreach (var newItem in newItems)
{
NewItem item = new NewItem
{
User = newItem.User,
Itemno = newItem.Itemno
};
db.NewItem.Add(item);
}
try
{
db.SaveChanges();
}
catch (Exception e)
{
Console.WriteLine(e);
}
I am getting the error:
Unable to update the EntitySet 'NewItem' because it has a
DefiningQuery and no element exists in the element to support the
current operation.
Why isn't the Add() method actually adding anything to my db context?
If the target database table doesn't have a primary key, add one.

Update multiple fields in SharePoint programmatically

I'm trying to update some properties on multiple fields (with the same name) in SharePoint.
I've tried this:
var site = this.Site.RootWeb;
var fields = site.Fields;
foreach (SPField field in fields)
{
if (field.Group.Contains("My Custom Columns"))
{
if (field.Title.Contains("Custom field"))
{
if (field.DefaultValue != null) {
field.DefaultValue = null;
field.Update(true);
}
}
}
}
It updates the first column with the name "Custom field", but after it's giving me this error:
Collection was modified; enumeration operation may not execute.
at Microsoft.SharePoint.SPBaseCollection.SPEnumerator.System.Collections.IEnumerator.MoveNext()
Is it not possible to Update the object in a foreach loop?
This error occurs since you are trying to modify a field collection while iterating it.
The solution would be to replace the line:
foreach (SPField field in fields)
with
foreach (var field in fields.Cast<SPField>().ToList())
The problem I believe is with your
foreach (SPField field in fields)
line of code. You are essentially modifying the collection that you are looping over.
What I would suggest you try is looping and getting the ID's of all the fields in to a
List<GUID>
Then do a foreach statement on this collection getting each field and updating it's value.
List<Guid> guidsList = new List<guid>();
foreach (SPField field in fields)
{
if (field.Group.Contains("My Custom Columns"))
{
if (field.Title.Contains("Custom field"))
{
guidsList.add(field.id)
}
}
}
foreach(Guid currentFieldId in guidsList){
//Get your field
//Update what needs to be updated
}
Many Thanks
Truez

Enumerating over Linq query results

I have some .NET 4.5 code:
var result = db.storedProcedure(param)
if (!result.Any()) { return; }
foreach (var entry in result)
{
// Some code...
}
At the foreach, an exception is throw:
The query results cannot be enumerated more than once.
How can I check if result is empty? I've also tried if (result.Count() == 0) and that also throws the same exception at the foreach loop. I've also tried foreach (var entry in result.ToList()) and that also throws the same exception.
I have tried following the suggestions here and here, with no luck.
I've also tried:
var result = db.storedProcedure(param)
if (!result.Any()) { return; }
var resultList = result.ToList();
foreach (var entry in resultList) {}
And I still get the same exception at that foreach loop as well.
There must be some way to easily check if a Linq result set is empty. What am I doing wrong?
Just put the result into a List before iterating:
var result = db.storedProcedure(param).ToList();
if (result.Count == 0) { return; }
Why do you even to make that check at all? Your loop won't even run at all if there's nothing in result. Just have this:
var result = db.storedProcedure(param)
foreach (var entry in result)
{
// Some code...
}
return;

Removing many to many entity Framework

There is a many to many relationship between Artist and ArtistType. I can easily add artist ArtistType like below
foreach (var artistType in this._db.ArtistTypes
.Where(artistType => vm.SelectedIds.Contains(artistType.ArtistTypeID)))
{
artist.ArtistTypes.Add(artistType);
}
_db.ArtistDetails.Add(artist);
_db.SaveChanges();
This goes and updates the many to many association table with correct mapping. But when I try to remove any item from table I do not get any error but it does not remove it from the table?
foreach (var artistType in this._db.ArtistTypes
.Where(at => vm.SelectedIds.Contains(at.ArtistTypeID)))
{
artistDetail.ArtistTypes.Remove(artistType);
}
this._db.Entry(artistDetail).State = EntityState.Modified;
this._db.SaveChanges();
What am I missing?
Standard way is to load the artist including the current related types from the database and then remove the types with the selected Ids from the loaded types collection. Change tracking will recognize which types have been removed and write the correct DELETE statements to the join table:
var artist = this._db.Artists.Include(a => a.ArtistTypes)
.SingleOrDefault(a => a.ArtistID == someArtistID);
if (artist != null)
{
foreach (var artistType in artist.ArtistTypes
.Where(at => vm.SelectedIds.Contains(at.ArtistTypeID)).ToList())
{
artist.ArtistTypes.Remove(artistType);
}
this._db.SaveChanges();
}
For removing only one field, I came up with this solution. It seems odd but in EF, most of the things are odd anyway because we try to tell EF the database ops in terms of OOP.
using (var db = new Context())
{
//Create existing entities without fetch:
var artist = new Artist() { ArtistID = _artistID };
var type = new Type() { TypeID = _typeID };
//Add one entity to other's list
//This is in memory, not connected.
//So we do this because we try to tell EF that we want to remove this item
//Without fetch, we should add it first in order to remove :)
artist.ArtistTypes.Add(type);
//Attach that entity which you add an item to its list:
db.Artists.Attach(artist);
//It's now connected and recognized by EF as database operation
//After attaching, remove that item from list and save db
artist.ArtistTypes.Remove(type);
db.SaveChanges();
}
That's it! With this solution, you are no longer fetching all entries of joined table ArtistTypes.

The query results enumerated more than once

datacontextclass dc=new datacontextclass ();
var news= dc.GetNewsCompany(Int64.Parse ( _idCompany));
if (news.GetEnumerator().MoveNext())
{
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}
}
return error:{"The query results cannot be enumerated more than once."}
how can check result != null in LINQ;
Using an enumerator wildly is a bad idea - for example, it needs disposing - which you haven't done (this could lead to a SqlDataReader being left open - not good). In this case, just enumerate it. If there aren't any records, that will be trivial:
if (news!=null)
{
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}
}
If you need the data twice, put it in a list:
var news = (blah).ToList();
You are creating the enumerator twice. The first is by calling news.GetEnumerator(), the second one happens behind the scenes in the foreach loop. The first "check" that you make with the call to MoveNext does not seem necessary (you will not go into the foreach unless there are items to iterate over), so just skip the if statement wrapping the loop:
datacontextclass dc = new datacontextclass();
var news = dc.GetNewsCompany(Int64.Parse(_idCompany));
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}
Change the second line of your code to
var news= dc.GetNewsCompany(Int64.Parse ( _idCompany)).toList();
it shall remove the issue.

Categories