Create or update if item exist - c#

I have a create form where if the specific Medicine exist, its number of supply will update or added with the new entry however if the specific Medicine doesn't exist, it will create a new batch of data.
Im having trouble at understanding how update works in MVC.
Here is the error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
Here is my controller:
public ActionResult Create([Bind(Include = "SupplyID,MedicineID,Expiration,NumberOfSupply")] Supply supply)
{
if (ModelState.IsValid)
{
bool supplyExsist = db.Supplies.Any(x => x.Expiration == supply.Expiration && x.MedicineID == supply.MedicineID);
if (supplyExsist)
{
var currentSupply = (from x in db.Supplies //get current supply
where x.MedicineID == supply.MedicineID
&& x.Expiration == supply.Expiration
select x.NumberOfSupply).First();
db.Entry(supply).State = EntityState.Modified;
supply.NumberOfSupply = currentSupply + supply.NumberOfSupply;
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
db.Supplies.Add(supply);
db.SaveChanges();
return RedirectToAction("Index");
}
}
ViewBag.MedicineID = new SelectList(db.Medicines, "MedicineID", "MedicineName", supply.MedicineID);
return View(supply);
}
Model:
public class Supply
{
[Key]
public int SupplyID { get; set; }
[ForeignKey("Medicine")]
public int MedicineID { get; set; }
public Medicine Medicine { get; set; }
[DataType(DataType.Date)]
public DateTime Expiration { get; set; }
[Display(Name = "Quantity")]
[Range(1, int.MaxValue, ErrorMessage = "The value must be greater than 0")]
public int NumberOfSupply { get; set; }
}

just try this
db.Supplies.AddOrUpdate(h => h.medicineID,supply));
it will check if there is a row with the same medicine ID in db if not it adds a new one else it updates it

You should change your if block with following :
if (supplyExsist)
{
var currentSupply = (from x in db.Supplies //get current supply
where x.MedicineID == supply.MedicineID
&& x.Expiration == supply.Expiration
select x.NumberOfSupply).First();
db.Supplies.Attach(supply);
db.Entry(supply).State = EntityState.Modified;
supply.NumberOfSupply = currentSupply + supply.NumberOfSupply;
db.SaveChanges();
return RedirectToAction("Index");
}

Related

Problem when Updating value (PUT) in ASP.NET core ef

I'm currently learning ASP.NET Core and having some problem. Basically, I have a model like this:
public class WorkRoom
{
[Key]
public int WorkRoomId { get; set; }
[ForeignKey("Room")]
[Required]
public int RoomId { get; set; }
public Room Room { get; set; }
[ForeignKey("Employee")]
[Required]
public string Id { get; set; }
public virtual ApplicationUser Employee { get; set; }
}
and a Dto for this model cause i only want to pass two value is RoomId and Id(using identityUser).
WorkRoomDto.cs
public class WorkRoomDto
{
public int RoomId { get; set; }
public string Id { get; set; }
}
I can write POST, GET and DELETE method normally as i wish, but I have some problems writing PUT.
public async Task<Response> PutWorkRooms(int id, WorkRoomDto workRoom)
{
var respone = new Response();
var workRoomId = _context.WorkRooms.Any(i => i.WorkRoomId == id);
var userId = await userManager.FindByIdAsync(workRoom.Id);
if (workRoomId)
{
if (userId == null)
{
respone.Status = false;
respone.Message = "User not exist";
return respone;
}
var newWorkRoom = mapper.Map<WorkRoomDto, WorkRoom>(workRoom);
_context.Entry(newWorkRoom).State = EntityState.Modified;
await _context.SaveChangesAsync();
respone.Status = true;
respone.Message = "Successfully updated.";
respone.Data = workRoom;
}
else
{
respone.Status = false;
respone.Message = "WorkRoomId no exist.";
}
return respone;
}
But it showed Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Before the autoMappter I had tried
_context.Entry(workRoom).State = EntityState.Modified;
await _context.SaveChangesAsync();
But it says the Dto is not in the DbContext. How can I fix this?
From your code, WorkRoomId is 0 in newWorkRoom. You need set the value for it. Just change like below:
var newWorkRoom = mapper.Map<WorkRoomDto, WorkRoom>(workRoom);
newWorkRoom.WorkRoomId = id; //add this line...
_context.Entry(newWorkRoom).State = EntityState.Modified;
await _context.SaveChangesAsync();
Automapper give you a brand new object that created locally (not taking back from the database), therefore, not tracked by the dbContext.
So, when you try to update newWorkRoom by forcing the state to modified, the dbContext know it want to see an update operation, but unfortunately, nothing got tracked, then execute nothing.
Try this
var newWorkRoom = mapper.Map<WorkRoomDto, WorkRoom>(workRoom);
if (_context.Entry(newWorkRoom).State == EntityState.Detached)
{
var entityFromDb = await _context.WorkRooms.FindAsync(id);
_context.Entry(entityFromDb).CurrentValues.SetValues(newWorkRoom);
}

DateTime in the transfer parameter of the edit method in the controller is always 01.01.0001 00:00:00 asp.net mvc5

I a problem in the transfer parameter in the Edit Method "issue".
In Issue the CreatedDate and UpdatedDate is always {01.01.0001 00:00:00}.
The parameter Id, Title and Description is always correct.
My Controller:
public ActionResult Edit([Bind(Include = "Id,Title,Description")] Issue issue)
{
if (ModelState.IsValid)
{
db.Entry(issue).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(issue);
}
My Model:
public class Issue : BaseEntity
{
public int Id { get; set; }
[Required(ErrorMessage = "Required")]
public string Title { get; set; }
[AllowHtml]
[Required(ErrorMessage = "Required")]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
}
public class BaseEntity
{
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
}
I can unfortunately can not debug from where the "issue" parameter comes from.
From where the transfer parameter "Issue issue" in the Edit method comes from and why are all DateTimes always {01.01.0001 00:00:00}?
When I create the first time a issue entity I add the DateTimme in the SaveChanges() Method with the following modification in my DBContext:
public override int SaveChanges()
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is BaseEntity && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
((BaseEntity)entityEntry.Entity).UpdatedDate = DateTime.UtcNow;
if (entityEntry.State == EntityState.Added)
{
((BaseEntity)entityEntry.Entity).CreatedDate = DateTime.UtcNow;
}
}
return base.SaveChanges();
}
And the SaveChanges() works without problem. When I create the issue entity the first time the DateTime has the correct value and I can also see it in the Detail View.
Change your edit code to this
var exist = d.Set<Issue>().FindAsync(issue.Id);
if (exist == null)
{
//ErrorMessage = "Can't find item to update";
}
else{
db.Entry(exist).CurrentValues.SetValues(issue);
var result = await db.SaveChanges(); // result should be > 0
}

Find method not assigning values to object

I have a web project that everything is working and this below line works for other models except for this one. I'm just needing some info on where to start looking for the solution at.
When I debug it I see that it is getting all the new data that has been edited but it does not assign the new data to EditedtimeEntry. The EditedtimeEntry var has the old data not the new data that was edited. I looked at the timeEntry.Id and it has the new edit its just not being assigned to the EditedtimeEntry. There is no exception or build errors it just does not save the changes, and it looks like the reason it is not save the changes is because the EditedtimeEntry var is not getting the new data assigned to it for some reason. Can anyone point me in the right direction?
TimeEntry EditedtimeEntry = db.TimeEntries.Find(timeEntry.Id);
Here is the Full method with the problem:
public ActionResult Edit( [Bind(Include = "Id,Description,Rate,Paid,Tech,Company")] TimeEntry timeEntry)
{
if (ModelState.IsValid)
{
TimeEntry EditedtimeEntry = db.TimeEntries.Find(timeEntry.Id);
Technician tech = db.Technician.Single(m => m.PhoneNumber == timeEntry.Tech.PhoneNumber);
EditedtimeEntry.Tech = tech;
Company comp = db.Companies.Single(m => m.Name == timeEntry.Company.Name);
EditedtimeEntry.Company = comp;
db.Entry(EditedtimeEntry).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(timeEntry);
}
I have other methods for other models that are identical to this one and it works. Here is alsos the model
public class TimeEntry
{
[Key]
public Guid Id { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string Description { get; set; }
public Rate Rate { get; set; }
public Technician Tech { get; set; }
public bool Paid { get; set; }
public Company Company { get; set; }
}
public enum Rate { Desktop, Network, Remote, Phone }
Thanks =)
Basically, what you are doing is exactly the contrary of what you want to do :) when you recover the item from the database, you are simply getting the item unchanged that is still in database. What you want is update the database item and then save changes (with EntityState.Modified then SaveChanges())
You simply want to edit timeEntry so that all changes done in the UI are translated into DB :
public ActionResult Edit( [Bind(Include = "Id,Description,Rate,Paid,Tech,Company")] TimeEntry timeEntry)
{
if (ModelState.IsValid)
{
Technician tech = db.Technician.Single(m => m.PhoneNumber == timeEntry.Tech.PhoneNumber);
timeEntry.Tech = tech;
Company comp = db.Companies.Single(m => m.Name == timeEntry.Company.Name);
timeEntry.Company = comp;
db.Entry(timeEntry).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(timeEntry);
}

PUT does not insert object in SQL Server

I'm having a problem with Web API where I want to create a new object in SQL Server.
The PUT method is used to update an expensenote. An expensenote contains dailyexpensenotes. A dailyexpensenote contains individualexpenses.
In the GUI, a user that edits his expensenote can:
Fill in an empty individualexpense with value > 0 (Creates a new individualexpense)
Change an existing individualexpense (Updates the existing individualexpense)
Clear an individualexpense/change value to 0 (Deletes the existing individualexpense)
After this the user clicks save and the entire expensenote is sent by ajax call to the web service. Nr 2 and Nr 3 are working as desired but the Nr 1 doesn't work and gives no error.
PUT method
// PUT api/expenses/5
public void Put(int id, [FromBody]Expensenote exUpdate)
{
expensenote ex = (from e in db.expensenotes
where e.ID == id
select e).FirstOrDefault();
if (ex == null)
{
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Request was not found.");
}
else
{
foreach (Expensenotedaily d in exUpdate.dailyExpenses)
{
var daily = ex.expensenotedailies.SingleOrDefault(da => da.ID == d.ID);
daily.city = d.city;
daily.dailyallowance = d.dailyallowance;
foreach (Expenseindividual i in d.individualExpenses)
{
expenseindividual individual = daily.expenseindividuals.SingleOrDefault(ind => ind.ID == i.ID);
if (i.value == 0)
{
if (!(individual == null))
{
db.expenseindividuals.Remove(individual);
}
}
else
{
if (!(individual == null))
{
individual.value = i.value;
}
else
{
expenseindividual newInd = db.expenseindividuals.Create();
newInd.typecode_ID = i.expensetypeID;
newInd.daily_ID = daily.ID;
newInd.typecode = db.typecodes.SingleOrDefault(t => t.ID == i.expensetypeID);
newInd.expensenotedaily = daily;
newInd.value = i.value;
newInd.creditcard = false;
db.expenseindividuals.Add(newInd);
//SOLUTION: db.SaveChanges();
}
}
}
}
db.SaveChanges();
}
}
expenseindividual datamodel class
public partial class expenseindividual
{
public expenseindividual()
{
this.supplementalinfoes = new HashSet<supplementalinfo>();
}
public int ID { get; set; }
public double value { get; set; }
public bool creditcard { get; set; }
public int daily_ID { get; set; }
public int typecode_ID { get; set; }
public virtual expensenotedaily expensenotedaily { get; set; }
public virtual typecode typecode { get; set; }
public virtual ICollection<supplementalinfo> supplementalinfoes { get; set; }
}
When I debug I see that all attributes are passed correctly.
Using newInd = new expenseindividual() instead of Create() doesn't fix the problem.
I tried setting the expenseindividual.ID manually and this makes the insert work but it must auto increment and auto increment is enabled.
So I'm really wondering what causes the problem here and how I can fix it?
If I understand you correctly, you are trying to insert a new expense note into the database when one does not already exist?
Firstly... this code currently ignores expense notes that do not already exist in the database...
expensenote ex = (from e in db.expensenotes
where e.ID == id
select e).FirstOrDefault();
if (ex == null)
{
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Request was not found.");
}
else
{
ex will always be null when you pass an id of an expense note that does not already exist inside of the database, therefore no code will be run.
The convention is that typically PUT is always used to update a record, POST is used instead when trying to create one but thats up to you.
You need to implement your logic to create a new record within the if statement, replacing the commented out return statement.

How to update foreign key using entitystate.modified?

I am new to MVC3 im trying to perform update function after edit which contents two foreign keys (BRANCH_ID,ITEM_MASTER_ID).
The problem im facing easy when branch_id or Item_master_id are not changed the row gets updated but if the foreigns keys change its throwing me an error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
Here is my model
public partial class MATERIAL
{
public int ID { get; set; }
public int ITEM_MASTER_ID { get; set; }
public int BRANCH_MASTER_ID { get; set; }
public string NAME { get; set; }
public string ADDRESS_DETAILS { get; set; }
public virtual BRANCH_MASTER BRANCH_MASTER { get; set; }
public virtual ITEM_MASTER ITEM_MASTER { get; set; }
}
My edit function code
[HttpPost]
public ActionResult Edit(MATERIAL material)
{
if (ModelState.IsValid)
{
db.Entry(material).State = EntityState.Modified;
db.SaveChanges();
int tempid = material.ID;
return RedirectToAction("listcontinue", new { id = tempid });
}
return View(material);
}
Help me in perform update even if my foreigns keys are changed.
here is my improved edit code
public ActionResult Edit(MATERIAL material)
{
var temp = Convert.ToString(material.ITEM_NAME);
using (var context = new material_managementEntities())
{
var temp1 = (from cs in context.ITEM_MASTER
where cs.ITEM_NAME == temp
select cs.ID).FirstOrDefault();
material.ITEM_MASTER_ID = temp1;
}
var temp2 = Convert.ToString(material.ITEMGROUP);
using (var context = new material_managementEntities())
{
var temp3 = (from cs in context.ITEM_GROUP_MASTER
where cs.ITEM_GROUP_NAME == temp2
select cs.ID).FirstOrDefault();
material.ITEM_MASTER_ITEM_GROUP_MASTER_ID = temp3;
}
if (ModelState.IsValid)
{
db.MATERIALs.Attach(material);
db.Entry(material).State = EntityState.Modified;
db.SaveChanges();
int tempid = material.ID;
return RedirectToAction("listcontinue", new { id = tempid });
}
return View(material);
}
I think you forgot to attach the object:
db.Materials.Attach(material);
db.Entry(material).State = EntityState.Modified;
db.SaveChanges();
I think in the context EF doesn't know about the foreign keys, I had to use an includes first before I update the foreign key:
db.Entry(team).State = EntityState.Modified;
db.SaveChanges();
var updatedTeam = db.Teams.Include(x=> x.GameType).Where(x=> x.ID == team.ID).Single();
updatedTeam.GameType = db.GameTypes.Find(GameTypeId);
db.SaveChanges();

Categories