Update a list of data in the database - c#

public ActionResult Event_History(int id = 0)
{
//set into false the active flag of the event
Events_Info_tbl events = db.Events_Info_tbl.Find(id);
events.is_active = false;
db.Entry(events).State = EntityState.Modified;
//set the category under this event into inactive
List<Events_Category_tbl> category = new List<Events_Category_tbl>();
category = db.Events_Category_tbl.Where(x=>x.events_info_id==id).ToList();
foreach(var i in category){
Events_Category_tbl cat = new Events_Category_tbl();
cat.is_active = false;
db.Entry(cat).State = EntityState.Modified;
}
db.SaveChanges();
TempData["MessageAlert"] = "Event is save in history!";
return RedirectToAction("Index");
}
Iam planning to set into inactive all the category belongs to that particular event but when I try to run this code an error displayed "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." pointing to this part of my code db.Entry(cat).State = EntityState.Modified;

foreach(var i in category){
Events_Category_tbl cat = new Events_Category_tbl();
cat.is_active = false;
db.Entry(cat).State = EntityState.Modified;
}
This part does not make any sense. You should not create a new instance of Events_Category_tbl.
You should instead just
foreach(var i in category){
i.is_active = false;
}

Below code try to create new object and save in DB, and all new object has same Id that's why give that error:
Events_Category_tbl cat = new Events_Category_tbl();
cat.is_active = false;
db.Entry(cat).State = EntityState.Modified;
You don't need to create new object, just update the retrieved entity:
public ActionResult Event_History(int id = 0)
{
//set into false the active flag of the event
var events = db.Events_Info_tbl.Find(id);
events.is_active = false;
//set the category under this event into inactive
var category = db.Events_Category_tbl.Where(x=>x.events_info_id==id).ToList();
foreach(var cat in category){
cat.is_active = false;
}
db.SaveChanges();
TempData["MessageAlert"] = "Event is save in history!";
return RedirectToAction("Index");
}

categories in a table may repeat themselves.... please replace:
db.Events_Category_tbl.Where(x=>x.events_info_id==id).ToList()
with
db.Events_Category_tbl.Where(x=>x.events_info_id==id).Distinct().ToList()
THAT WAY YOU WILL MAKE SURE THAT EVERY ITEM REPEAT ONLY ONCE

Related

Trying to Add to Database: Collection was modified; enumeration operation may not execute?

Below is my controller That I am calling from a href button and passing an id. The href button is a duplicate button which is meant to create a copy of the selected module and add it to the database and then return it.
public ActionResult dupe(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
MODULE Modules = db.MODULE.Find(id);
if (Modules == null)
{
return HttpNotFound();
}
else
{
MODULE newMOd = new MODULE();
newMOd.APPLY__FINISH = Modules.APPLY__FINISH;
newMOd.CREATED_BY = Modules.CREATED_BY;
newMOd.CREATED_DATE = Modules.CREATED_DATE;
newMOd.MODULE_DESC = "Duplicate-"+Modules.MODULE_DESC;
newMOd.MODULE_TYPE = Modules.MODULE_TYPE;
newMOd.MODULE_TYPE1 = Modules.MODULE_TYPE1;
newMOd.PRODUCT_LINE = Modules.PRODUCT_LINE;
newMOd.MODULE_NAME = "Duplicate-" + Modules.MODULE_NAME;
foreach (MODULE_PARTS mp in Modules.MODULE_PARTS)
{
newMOd.MODULE_PARTS.Add(mp);
}
foreach (MODULE_OPTION mo in Modules.MODULE_OPTION)
{
MODULE_OPTION m = new MODULE_OPTION();
m.OPTION_NAME = mo.OPTION_NAME;
m.OPTION_TYPE = mo.OPTION_TYPE;
m.PRODUCT_LINE = mo.PRODUCT_LINE;
m.ADDED_BY = mo.ADDED_BY;
m.ADDED_ON = mo.ADDED_ON;
m.DEFAULT_FACTOR = mo.DEFAULT_FACTOR;
foreach (OPTION_PARTS op in mo.OPTION_PARTS)
{
m.OPTION_PARTS.Add(op);
}
newMOd.MODULE_OPTION.Add(mo);
}
newMOd.MODULE_PARTS = Modules.MODULE_PARTS;
newMOd.MODULE_OPTION = Modules.MODULE_OPTION;
db.MODULE.Add(newMOd);
db.SaveChanges();
}
return View(Modules);
}
This is my controller method, and when I try to add this module to database I get collection modified error. I'm not sure how or where?
enter image description here
The exception message in this case is quite clear... you cannot modify a member of a collection you are currently iterating over. It's that simple.

How to stop Entity Framework holding on to record from database?

I'm working on ASP.NET Boilerplate. I have the problem where I try to get a record from a table called Buildings and make an update on it. I get the record from database by:
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
And after that, I make some changes on the data as follows:
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
And then copy the buildingApp to another object, which has the same properties, in order to pass the new object to update method as follows:
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
And the update method is as follows:
_buildingsAppService.update(updateBuildingInput);
The problem is when it executes the previous line, I get the following error:
System.InvalidOperationException: 'Attaching an entity of type 'TaawonMVC.Models.Buildings' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.'
I can see that when I initialize the object updateBuildingInput manually, the update method runs without error. But when it depends on the object obtained from database using buildingApp, the error happens. It seems like the get method gets data from database and keeps holding on to the record from database, and when I try to update the same record, the conflict happens. This is the whole action where all of get and update happens:
public ActionResult UpdateApplication (UpdateApplicationsInput model)
{
var updateApplication = new UpdateApplicationsInput();
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
//==== get building and unit related to application for update ======
var buildingInput = new GetBuidlingsInput()
{
Id = updateApplication.buildingId
};
var buildingUnitInput = new GetBuildingUnitsInput()
{
Id = updateApplication.buildingUnitId
};
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
var buildingUnitApp = _buildingUnitsAppService.GetBuildingUnitsById(buildingUnitInput);
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
// buildingUnitApp.BuildingId = updateApplication.buildingId;
buildingUnitApp.ResidenceStatus = Request["residentstatus"];
// copy object getBuildingUnitInput to updateBuildingUnitInput
var updateBuildingUnitInput = new UpdateBuildingUnitsInput()
{
BuildingId = buildingUnitApp.BuildingId,
ResidentName = buildingUnitApp.ResidentName,
ResidenceStatus = buildingUnitApp.ResidenceStatus,
NumberOfFamilyMembers = buildingUnitApp.NumberOfFamilyMembers,
Floor = buildingUnitApp.Floor,
UnitContentsIds = buildingUnitApp.UnitContentsIds
};
//============================================
// copy object from getBuildingOutput to updateBuildingInput
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
//======================================================
updateApplication.Id = Convert.ToInt32(Request["applicationId"]);
updateApplication.fullName = model.fullName;
updateApplication.phoneNumber1 = model.phoneNumber1;
updateApplication.phoneNumber2 = model.phoneNumber2;
updateApplication.isThereFundingOrPreviousRestoration = model.isThereFundingOrPreviousRestoration;
updateApplication.isThereInterestedRepairingEntity = model.isThereInterestedRepairingEntity;
updateApplication.housingSince = model.housingSince;
updateApplication.previousRestorationSource = model.previousRestorationSource;
updateApplication.interestedRepairingEntityName = model.interestedRepairingEntityName;
updateApplication.PropertyOwnerShipId = Convert.ToInt32(Request["PropertyOwnerShip"]);
updateApplication.otherOwnershipType = model.otherOwnershipType;
updateApplication.interventionTypeId = Convert.ToInt32(Request["interventionTypeName"]);
updateApplication.otherRestorationType = model.otherRestorationType;
updateApplication.propertyStatusDescription = model.propertyStatusDescription;
updateApplication.requiredRestoration = model.requiredRestoration;
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
// ==== get of restoration types which it is multi select drop down list ======
var restorationTypes = Request["example-getting-started"];
string[] restorationTypesSplited = restorationTypes.Split(',');
byte[] restorationTypesArray = new byte[restorationTypesSplited.Length];
for (var i = 0; i < restorationTypesArray.Length; i++)
{
restorationTypesArray[i] = Convert.ToByte(restorationTypesSplited[i]);
}
updateApplication.restorationTypeIds = restorationTypesArray;
// ====== end of RestorationTypes
_buildingsAppService.update(updateBuildingInput);
_applicationsAppService.Update(updateApplication);
// _buildingUnitsAppService.Update(updateBuildingUnitInput);
// ==== get list of applications ==============
var applicationsUpdate = _applicationsAppService.getAllApplications();
var applicationsViewModel = new ApplicationsViewModel()
{
Applications = applicationsUpdate
};
return View("Applications", applicationsViewModel);
}
How ASP.NET Boilerplate template, which I use, makes CRUD Operation to database:
public class BuildingsManager : DomainService, IBuildingsManager
{
private readonly IRepository<Buildings> _repositoryBuildings;
public BuildingsManager(IRepository<Buildings> repositoryBuildings)
{
_repositoryBuildings = repositoryBuildings;
}
// create new building in table buildings .
public async Task<Buildings> create(Buildings entity)
{
var building = _repositoryBuildings.FirstOrDefault(x => x.Id == entity.Id);
if(building!=null)
{
throw new UserFriendlyException("Building is already exist");
}
else
{
return await _repositoryBuildings.InsertAsync(entity);
}
}
// delete a building from buildings table .
public void delete(int id)
{
try
{
var building = _repositoryBuildings.Get(id);
_repositoryBuildings.Delete(building);
}
catch (Exception)
{
throw new UserFriendlyException("Building is not exist");
}
}
public IEnumerable<Buildings> getAllList()
{
return _repositoryBuildings.GetAllIncluding(b => b.BuildingType, n => n.NeighboorHood,u=>u.BuildingUses);
}
public Buildings getBuildingsById(int id)
{
return _repositoryBuildings.Get(id);
}
public void update(Buildings entity)
{
_repositoryBuildings.Update(entity);
}
}
How can I solve this problem? Many thanks for help.
By creating a new entity (updateBuildingInput) with the same primary key as one you have already read in your context, Entity will throw an error when you attempt an operation on the new entity (as you have seen) as it is already tracking an entity with that primary key in the context.
If _buildingsAppService is a DbContext and all you need to do is make some changes to an entity, you can:
Read the entity
Make changes directly to that entity object
Call _buildingsAppService.SaveChanges()
SaveChanges() will:
Saves all changes made in this context to the underlying database.
When getting the record from db you can use .AsNoTracking()
Or if you really need to update an attached entity first locate the attached copy and detach it, then modify and update;
public async Task<bool> UpdateAsync<T>(T entity)
where T : class, IHasId
{
// check if entity is being tracked
var local = _context.Set<T>().Local.FirstOrDefault(x => x.Id.Equals(entity.Id));
// if entity is tracked detach it from context
if (local != null)
_context.Entry<T>(local).State = EntityState.Detached;
_context.Attach(entity).State = EntityState.Modified;
var result = await _context.SaveChangesAsync();
// detach entity if it was not tracked, otherwise it will be kept tracking
if(local == null)
_context.Entry(entity).State = EntityState.Detached;
return result > 0;
}
btw, IHasId is a simple interface to make Id property accessible for generic types;
public interface IHasId {
int Id { get; set; }
}
Use .AsNoTracking():
public class BuildingsManager : DomainService, IBuildingsManager
{
public Buildings getBuildingsById(int id)
{
return _repositoryBuildings.GetAll().AsNoTracking().First(b => b.Id == id);
}
// ...
}

Enter new data in db (EF)

I have method in controller
It receive data from post request and write to table
Here is code
[ResponseType(typeof(TimeTable))]
public IHttpActionResult PostTimeTable(TimeTable timeTable)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (ModelState.IsValid)
{
DateTime dt = DateTime.Today;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).First();
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
db.SaveChanges();
}
db.TimeTables.Add(timeTable);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = timeTable.Id }, timeTable);
}
But it works well when record with INN and Company already in db.
But if it not in database I need to create new entry.
How I need to modify this method?
You can use a flag (exisingCompanyFlag) for edit mode or add new mode like this
bool existingCompanyFlag = true;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).FirstOrDefult();
if (c == null)
{
existingCompanyFlag = false;
c = new TimeTable();
}
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
if (!existingCompanyFlag)
db.TimeTables.Add(c);
You need a separate branch in your code for the insert case.
if (ModelState.IsValid) {
if (addingNewRow) {
TimeTable tt = new TimeTable {
// Populate properties (except identity columns)
};
db.TimeTables.Add(tt);
} else {
// update
}
db.SaveChanges();
}
To link to other entities use one of:
Assign instances:
x.Company = theCompany;
or, assign the instance id
x.CompanyId = companyId;
(#1 is easier if you already have the other entity loaded or are creating it – EF will sort out the ids – while #2 saves loading the whole other entity.)

Update multiple columns in Entity Framework

I want to update multiple columns in Entity Framework. I now use this :
var user = new Relations { Id=1, Status = 1, Date = DateTime.Now, Notification = 0 };
db.Relations.Attach(user);
db.Entry(user).Property(x => x.Status).IsModified = true;
db.Entry(user).Property(x => x.Notification).IsModified = true;
db.Entry(user).Property(x => x.Date).IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
Is there a better way to update columns without repeating the code db.Entry(user).Property several times ?
you can Use EntityState Like this:
var user=db.users.Find(userId);
user.name="new name";
user.age=txtAge.text;
user.address=txtAddress.text;
context.Entry(user).State=Entitystate.Modified;
I prefer use:
var existingUser = context.Set<User>().Where(u => u.Id == 1);
context.Entry(existingUser).CurrentValues.SetValues(user);
Or you can use a 3rd lib like GraphDiff.
Yo update an entity you don't need to do this:
// build your entity object with new values
var user = new Relations { Id=1, Status = 1, Date = DateTime.Now, Notification = 0 };
//attach as modified in one single step
db.Entry(user).State = EntityState.Modified;
//execute update
db.SaveChanges();
This assumes you are setting all entity fields and there isn't RowVersion field in your entity. Extra steps would be required to manage these other situations.
Try this,
using (var db = new YourDb())
{
try
{
db.Entry(user).State = EntityState.Modified;
}
catch (Exception)
{
return false;
}
db.SaveChanges();
return true;
}
When an item is fetched via the context it is
automatically tracked in that context unless you change the default behavior.
So you could simple do:
var txtInputAge = 18;
var txtAdrressLine1 = "Some cool place"
//fetch the user
var user = db.Users.Find(userId);
//change the properties
user.Name = "new cooler name";
user.Age = txtInputAge;
user.Address = txtAdrressLine1;
//call save changes
db.SaveChanges();
Update - Add would look like
//create new entry
User user = new User();
user.Name = "new cooler name";
user.Age = txtInputAge;
user.Address = txtAdrressLine1;
//add to context
db.Users.Add(user);
//call save changes
db.SaveChanges();
using (var dbcontext = new MyModel())
{
var matchedRecords = dbcontext.DummyTable.Where(e => e.code.Equals(entry.code) &&
e.isValid.Equals(true)).ToList();
matchedRecords.ForEach(e => e.isValid = false);
dbcontext.SaveChanges();
}

Persisting data in ASP.NET MVC

I'm having some issues in updating and inserting records using ASP.NET MVC and Entity Framework.
I have a form (which is a report) that is dynamically created and can have any amount of questions. I'm trying to allow the user to edit the report and submit the changes so that it is updated in the database.
I am retrieving the report to be edited from the database via a repository then setting it to an instance of ModeratorReport. I'm then changing the value of the properties and using db.SaveChanges to save the changes to the database.
The problem is that it is not saving the changes.
Please could someone advise me on what I am doing wrong?
Here is the Edit Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection formCollection, int moderatorReportId, string status)
{
ModeratorReport reportToEdit = repository.GetModeratorReportById(moderatorReportId);
List<QuestionAnswer> originalReportAnswers = repository.GetAllModeratorReportAnswers(moderatorReportId, status).ToList();
foreach (QuestionAnswer answer in originalReportAnswers) {
reportToEdit.QuestionAnswers.Remove(answer);
}
int sectionID;
int questionID;
foreach (string key in formCollection.AllKeys)
{
var value = formCollection[key.ToString()];
Match m = Regex.Match(key, "section(\\d+)_question(\\d+)");
if (m.Success) {
QuestionAnswer newAnswer = new QuestionAnswer();
sectionID = Convert.ToInt16(m.Groups[1].Value.ToString());
questionID = Convert.ToInt16(m.Groups[2].Value.ToString());
newAnswer.ModeratorReportID = moderatorReportId;
newAnswer.SectionID = sectionID;
newAnswer.QuestionID = questionID;
newAnswer.Answer = value;
newAnswer.Status = "SAVED";
reportToEdit.QuestionAnswers.Add(newAnswer);
}
}
reportToEdit.Status = "SAVED";
AuditItem auditItem = new AuditItem();
auditItem.ModeratorReportID = moderatorReportId;
auditItem.Status = "SAVED";
auditItem.AuditDate = DateTime.Now;
auditItem.Description = "The Moderator report..."
auditItem.UserID = User.Identity.Name;
reportToEdit.Audit.Add(auditItem);
db.SaveChanges();
return RedirectToAction("Details", new { id = moderatorReportId });
}
The problem looks like you're just not setting reportToEdit's EntityState to modified. Like so:
reportToEdit.Audit.Add(auditItem);
reportToEdit.EntityState = EntityState.Modified;
db.SaveChanges();
For more information about the EntityState enumeration, see this MSDN article.

Categories