Cannot update a record in Entity Framework 5 - asp.net-mvc

I have the following method in the repository and I need to update an Entity.
Unfortunately I cannot update the record (no errors message).
Any idea what am I doing wrong?
public void Update(GaLocation entity)
{
context.GaLocations.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();
}

This is how I update entries:
public void Update(GaLocation entity)
{
GaLocation gl = context.GaLocations.Where(h=>h.id == entity.id).FirstOrDefault();
gl.val1 = entity.val1;
gl.val2 = entity.val2;
//etc
context.SaveChanges();
}
I've tried using Attach, but I've run into issues with that too. I'm sure it works, but this way worked better for me.

Related

How to permanently delete values from the database

I have a method that i call from a javascript, the method suppose to delete the records permanently but it does not go in to the method if the method has DataContext db = new DataContext();, it gives the error Internal Server Error
public void PermanantlyDeleteComment(GetCommentInput input)
{
DataContext db = new DataContext();
//Follow by the code to delete the comment
}
If i comment out DataContext db = new DataContext(); the breakpoint does go in.
I think the problem is with the datacontext but i do know know where
Here is the datacontext
public DataContext() : base("name=Default")
{
this.Configuration.AutoDetectChangesEnabled = true;
this.Configuration.LazyLoadingEnabled = true;
}
I'm using DataContext because abp boilerplate does not want to permanently delete, only soft delete, if you have a way that i can hard delete with boilerplate please let me know.
Answered in this topic: https://forum.aspnetboilerplate.com/viewtopic.php?p=6180#p6193
You can override CancelDeletionForSoftDelete method in your DbContext and prevent cancellation conditionally.
So, like this:
protected override void CancelDeletionForSoftDelete(EntityEntry entry)
{
if (IsSoftDeleteFilterEnabled)
{
base.CancelDeletionForSoftDelete(entry);
}
}
Usage:
public void PermanantlyDeleteComment(GetCommentInput input)
{
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.SoftDelete))
{
// The code to delete the comment
}
}
I found out that the DataContext was correct, is just i had different EntityFramework version on my Database Library (which has DataContext.cs) and my Web Library

ExecuteSqlCommand automatically calls SaveChanges() when I don't want it to

In my ASP.NET MVC project using Entity Framework 5, I have one operation that I want to perform with a back-end stored procedure, because it affects a number of different entities. The nature of the stored procedure is that I don't need or want it to be tracked by EF; I call it from one entity, and then that entity's values are copied into a different table in the database. The problem is that I can't seem to stop EF from calling SaveChanges(), even though I don't want it to.
Here's a truncated version of my repository code:
public class SubmissionRepository : IRepository<RebateHeaderSubmission>
{
private readonly HbaRebatesContext _db;
public SubmissionRepository()
{
_db = new HbaRebatesContext();
}
public void Add(RebateHeaderSubmission entity) . . .
public RebateHeaderSubmission GetById(int id) . . .
public IQueryable<RebateHeaderSubmission> GetAll() . . .
public void Update(RebateHeaderSubmission entity) . . .
public void Save()
{
_db.SaveChanges();
}
public void AcceptSubmission(RebateHeaderSubmission entity)
{
var param = new SqlParameter("Rebate_Entry_Id", entity.Id);
_db.Database.ExecuteSqlCommand("EXEC dbo.AcceptSubmission #Id", param);
}
}
}
And here's a slightly-truncated version of the code that calls AcceptSubmission():
public ActionResult Edit(RebateHeaderSubmission editedRecord, bool acceptSubmission = false)
{
if (editedRecord.Id > 0 && ModelState.IsValid)
{
_db.Update(editedRecord);
}
else
{
return PartialView("_Edit", editedRecord);
}
_db.Save();
if (acceptSubmission == false)
{
return RedirectToAction("Single", new { id = editedRecord.Id });
}
else
{
var repo = _db as SubmissionRepository;
if (repo != null)
{
repo.AcceptSubmission(editedRecord);
}
return RedirectToAction("Single", new { id = editedRecord.Id });
}
}
But in AcceptSubmission(), as soon as _db.Database.ExecuteSqlCommand is called, the execution jumps up to the Save() method and I get a DbUpdateConcurrencyException saying that no rows were updated.
I've tried updating the method to detach the entity, but it hasn't done any good. This was the attempt I was most hopeful about:
public void AcceptSubmission(RebateHeaderSubmission entity)
{
try
{
var param = new SqlParameter("Rebate_Entry_Id", entity.Id);
var context = ((IObjectContextAdapter)_db).ObjectContext;
context.SaveChanges();
context.Detach(entity);
_db.Database.ExecuteSqlCommand("EXEC dbo.AcceptSubmission #Rebate_Entry_Id", param);
}
catch (DbUpdateConcurrencyException)
{
//Do nothing for now.
}
}
The execution still jumps up to Save(), and my catch block doesn't even work, because the exception happens in the Save() method instead. Is there anyway to get EF to stop calling SaveChanges()?
UPDATE: Two small clarifications. First, the stored procedure I'm calling is being executed, and it works. So AcceptSubmission() is working. Second, when I say that execution "jumps" to Save(), what actually happens is that as soon as I've run _db.Database.ExecuteSqlCommand, an exception is raised, but it's raised in the Save() method. I don't actually hit the end bracket for AcceptSubmission(), nor the opening bracket for Save().
It turns out I was mis-diagnosing the problem. EF wasn't "jumping" to SaveChanges. There were actually two active threads, caused by an error with Unobtrusive JavaScript, such as described in this answer. Fixing the error in my JavaScript fixed the problem.

How to check the original value of an attribute using MVC and EF

Need to compare the original value with the current value in order to do some updates on objects prior to save changes. How to get the original value of an object? The following does not work:
public ActionResult Edit(int id = 0)
{
Project project = db.Projects.Find(id);
...
db.Projects.Attach(project); // ATTACH here
...
}
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
db.Entry(project).State = EntityState.Modified; // The STATE was DETACHED here...
...
}
Is this a configuration issue, or did I miss something? Thanks in advance for any help!
The problem with your solution is the lifetime of the controller. By default a new instance of the controller is generated for each client request. This means that you need to load the original value inside the POST method of edit, because you cannot share the instance of your context.
I have edited the code sample after #Gerard's comment
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
var original_value = db.Projects.Find(project.ProjectId);
or
var original_value_detached = db.Projects.AsNoTracking().Where(P => P.ProjectId == project.ProjectId).FirstOrDefault();
}
}
Or you write your own implementation of the controller factory to share you context between two requests, but you should consider requests from different clients. You can find an example here
It looks like you are implementing concurrency. May be, you can try to catch your changes using DbUpdateConcurrencyException. Something like this:
try
{
...
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var dbValue = (Project)entry.GetDatabaseValues().ToObject();
if(dbValue.State == EntityState.Modified)
{
//***your code
}
}

Adding record duplicates other object using entity framework

I am trying to add a new record in an MVC controller method using Entity framework.
When i just used "InsertOrUpdate" the audittype got duplicated. Based on the answer from Entity Framework adding record with a related object i hoped to fix it pretty qiock. This is the code I have right now:
Controller:
if (ModelState.IsValid)
{
Audit newAudit = Factory.GetNew();
newAudit.Name = model.Name;
newAudit.Deadline = model.Deadline;
newAudit.AuditType = auditTypeRepository.Find(model.SelectedAuditTypeId);
Repository.InsertOrUpdate(newAudit);
Repository.Save();
return RedirectToAction(MVC.Audits.Details(newAudit.Id));
}
Repository:
public override void InsertOrUpdate(Qdsa.WebApplications.AuditMaster.Data.Audit model)
{
if (model.Id == default(int))
{
// New entity
context.Audits.Add(model);
}
else
{
// Existing entity
model.ModifiedOn = DateTime.Now;
context.Entry(model).State = EntityState.Modified;
}
//If I leave out the code below the AuditType will be duplicated
if (model.AuditType != null)
{
context.Entry<AuditType>(model.AuditType).State = EntityState.Unchanged;
}
}
public virtual void Save()
{
context.SaveChanges();
}
So i thought I fixed the problem. However, AuditType has Child objects too. And now these childobjects get duplicated.
What is the right way to add entities with child objects which already exists?
Because the AuditType is required I can't save it without first and then update it. any suggestions?
UPDATE:
Both the AuditRepostory and the AuditTypeRepository inherit from BaseRepository which has the context as:
protected DBContext context = new DBContext ();
public virtual T Find(int id)
{
return All.SingleOrDefault(s => s.Id == id);
}
I can imagine two reasons for the problem:
Either auditTypeRepository.Find performs a no tracking query (with .AsNoTracking())
Or you are using a context instance per repository, so that Repository and auditTypeRepository are working with two different contexts which will indeed result in a duplication of the AuditType because you don't attach it to the the context that corresponds with Repository (except in the line with your comment).
If the latter is the case you should rethink your design and inject a single context instance into all repositories instead of creating it inside of the repositories.
I think the problem is from here:
newAudit.AuditType = auditTypeRepository.Find(model.SelectedAuditTypeId);
Change that like this:
newAudit.AuditTypeId = model.SelectedAuditTypeId;

"An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported."

When I run following code:
public ActionResult Complete()
{
try
{
VeriTabanDataContext db = new VeriTabanDataContext();
db.Persons.InsertOnSubmit(_person);
db.SubmitChanges();
return View(_person);
}
catch (Exception ex)
{
return RedirectToAction("Error", ex);
}
}
I'm getting following Exception, on SubmitChanges();
"An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported."
Here "_person" object is taken from Session and is a good standing. Note: _person is a result of multistep wizard and this is the place where I add new Person object to the DB.
My Person table has 9 relations and it's not ok for me to add version column for each of them as is suggested by some geeks around
I've investigated this problem a lot and spend 2 days on it and still couldn't solve it. Some of the workarounds that other suggest don't solve my problem, and others seem to be just dirty workaround. Do you experts have a good solution for this problem, considering that Person class has many relations and also it isn't ok to add a column to the tables.
I also want to note that I've tried to use 'db.Persons.Attach(_person) ' and setting db.DeferredLoadingEnabled = false; THis time I'm not getting any Exception but data is NOT saved to DB
I create a class called applicationController which derives from Controller. Then i make all of my controller classes derive from this. The applicationController class has a constrcutor which creates a new instance of my repository (or datacontext in your instance) which is used throughout the application:
public class ApplicationController : Controller
{
private VeriTabanDataContext _datacontext;
public ApplicationController() : this(new VeriTabanDataContext())
{
}
public ApplicationController(VeriTabanDataContext datacontext)
{
_datacontext = datacontext;
}
Public VeriTabanDataContext DataContext
{
get { return _datacontext; }
}
}
Then you can use this in all of your controllers
public class MyController : ApplicationController
{
public ActionResult Complete()
{
DataContext.Persons.InsertOnSubmit(_person);
DataContext.SubmitChanges();
return View(_person);
}
}
Not on my PC with VS installed at the moment so not tested this code....
Hope this resolves the issue -Mark
Can you do the following:
var foundPerson = db.Person.FirstOrDefault( p => p.Id == _person.Id);
if(foundPerson == null)
{
db.InsertOnSubmit(_person);
}else{
Mapper.Map(_person,foundPerson);
}
db.SubmitChanges();
return View(_person);
Where I have used AutoMapper to map from one entity to another. To do this add the reference to AutoMapper to your project and in your start up code for the application you will need to configure your mappings, for the above to work you would need:
Mapper.CreateMap<Person, Person>().ForMember(src => src.Id, opt => opt.Ignore());

Resources