Insert Multiple Rows to Database LINQ - c#

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.

Related

Use of using statement for Entity Framework DbContext in foreach-loop

There is a parser that parses a text file which contains object definition. The object definitions in the text file have a placeholder handle key. The place holder handle needs to be replaced with actual value by looking up the handle value in DB. In my application I am making use of the Entity framework Core for working with the DB.
The parser returns one object at a time, and I am looking up the handle and other properties in the DB one at a time. This is how the code looks so far:
IEnumerable<ObjectInfo> GetNextContent();
IEnumerable<ObjectInfo> GetNextObjectInfo()
{
foreach (var item in parser.GetNextContent())
{
using (var dbContext = new ContentDbContext())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}
}
}
The question that I have is that in the code above, the 'using' block is within the foreach loop.
Is this a right thing to do?
The other thought is that I can take the 'using' block outside of the foreach-loop but then I am not sure how would that play out with the iterator in the code.
You should move ContentDbContext into outside for better performance.
This is simply because You just need one context per request.
One DbContext per web request... why?
using (var dbContext = new ContentDbContext())
{
foreach (var item in parser.GetNextContent())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}
}
Updated
You might also join then make sure that fetch all data at a time
// You need to fetch all `item.Key` from `parser.GetNextContent()` to get all data in `dbContext.Contents`
var keys = parser.GetNextContent().Select(p => p.Key).ToArray();
var result = (from content in dbContext.Contents
join key in keys on content.Id equals key
select new
{
Id = content.ObjectId,
//....
}
If you are use C# 8, using statement may be as below:
using var dbContext = new ContentDbContext();
foreach (var item in parser.GetNextContent())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}

Issue with removing records in EF

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);
}

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

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 result of a query cannot be enumerated more than once

I am using the entity framework (ef) and am getting the following error:
"The result of a query cannot be enumerated more than once.".
I have a repository class which contains the ef data context. I then have a controller class (not to be confused with MVC controllers) which contains an instance of the repository. So far so good... I have a search method on the controller which is supposed to return an array of RadComboBoxItemData, which is used to populate a Telerik RadComboBox control.
public RadComboBoxItemData[] Search(int id, string searchText)
{
var query = context.Search(id, searchText);
List<RadComboBoxItemData> result = new List<RadComboBoxItemData>();
foreach (var item in query)
{
RadComboBoxItemData itemData = new RadComboBoxItemData();
itemData.Text = ""; // assign some text here..;
itemData.Value = ""; /*assign some value here..*/
result.Add(itemData);
}
return result.ToArray();
}
When I debug my code, I can get into the foreach loop, but then I get an error saying:
An exception of type
'System.InvalidOperationException'
occurred in System.Data.Entity.dll but
was not handled in user code
Additional information: The result of
a query cannot be enumerated more than
once.
My entity uses a function import of an existing stored proc.
// EF repository method calling the function imported method on the data context.
public IEnumerable<SearchItem> Search(int id, string searchText)
{
return this.entityContext.Search(id, searchText);
}
The function import Search calls a stored precedure to return a collection of SearchItem.
I have a feeling that the foreach loop can't iterate because of something with the ef.
Try explicitly enumerating the results by calling ToList().
Change
foreach (var item in query)
to
foreach (var item in query.ToList())
Try replacing this
var query = context.Search(id, searchText);
with
var query = context.Search(id, searchText).tolist();
and everything will work well.
Problematic code calling an stored procedure:
var resultSP = db.StoredProcedure(id);
if (resultSP != null)
{
var count = resultSP.Count();
var list = resultSP.Select(x=>...);
}
Fixed, store in a variable with ToList() and reuse it:
var resultSP = db.StoredProcedure(id);
if (resultSP != null)
{
var resultSP_List = resultSP.ToList();
var count = resultSP_List.Count();
var list = resultSP_List.Select(x=>...);
}
if you getting this type of error so I suggest you used to stored proc data as usual list then binding the other controls because I also get this error so I solved it like this
ex:-
repeater.DataSource = data.SPBinsReport().Tolist();
repeater.DataBind();
try like this

Categories