locked
Need help troubleshooting this Method. RRS feed

  • Question

  • User1901201124 posted

    Hi There guys, Something has been confusing me. I created a method within my controller and I am calling it from Javascript Json/Ajax in my view page.

    The purpose of this method is to set the Status of the DB field to Archive and then update my Audit table to denote the original data and new data.

    But every time I call this method it inserts into the database with the same data, old and new are the same. (both having status of Archive where only the new record should have that and not the old).

    Hope that makes  sense and someone could help me out would be appreciated. Thanks!

            [HttpPost]
            public JsonResult ArchiveRecord(int id)
            {
                // Audit Process 1. Gather old values
                var original_data = db.StudentRec.AsNoTracking().Where(P => P.ID == id).FirstOrDefault();
    
                StudentRec NewRecord = original_data;
                NewRecord.StudentStatus = "Archive";
    
                db.Entry(NewRecord).State = EntityState.Modified;
                db.SaveChanges();
    
                Audit history = new Audit();
                history.CreateAuditTrail(AuditActionType.Update, id, original_data, NewRecord);
    
                return Json(id, JsonRequestBehavior.AllowGet);
            }

    Tuesday, February 26, 2019 8:37 PM

Answers

  • User475983607 posted

    You're creating references to the same object in memory (reference type).  Simply create a new Audit record form the original student by assigning the student properties values to the Audit entity (not sure what the name is).  Similar to the following code.

    [HttpPost]
    public JsonResult ArchiveRecord(int id)
    {
    	// Get the student
    	var student = db.StudentRec.Where(P => P.ID == id).FirstOrDefault();
    	
    	//Set the audit fields from the student 
    	AuditEntity audit = new AuditEntity()
    	{
    		StudentId = student.Id,
    		OtherField = student.OtherField
    	}
    
    	//Update the student entity
    	student.StudentStatus = "Archive";
    	
    	//Save both records
    	db.Entry(AuditEntity).State = EntityState.Added;
    	db.SaveChanges();
    
    	return Json(id);
    }

    The docs explain the same.

    https://docs.microsoft.com/en-us/ef/ef6/saving/change-tracking/entity-state

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, February 26, 2019 9:26 PM
  • User1120430333 posted

    You should only be dealing wit the ordinal object you got in context.

    var original_data = db.StudentRec.AsNoTracking().Where(P => P.ID == id).FirstOrDefault();
    
                StudentRec NewRecord = original_data;
                NewRecord.StudentStatus = "Archive";
    
                db.Entry(NewRecord).State = EntityState.Modified;
                db.SaveChanges();

    So you supposedly copied 'original' to 'new', but they are the same object, the 'original'. And then you changed data and  state on 'new' that is really the 'orig'. And based on the primary ID of the object in 'new' that came from 'orig', it updated by ID the data table record in the database the 'original' data in the table record.

    Do you see what I am saying? The new and orig object have the same primary-key property that points back to the primacy-key ID of the record setting in the database table, which is the original data in the table record that  is being updated by primary-key ID.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, February 26, 2019 9:36 PM

All replies

  • User475983607 posted

    You're creating references to the same object in memory (reference type).  Simply create a new Audit record form the original student by assigning the student properties values to the Audit entity (not sure what the name is).  Similar to the following code.

    [HttpPost]
    public JsonResult ArchiveRecord(int id)
    {
    	// Get the student
    	var student = db.StudentRec.Where(P => P.ID == id).FirstOrDefault();
    	
    	//Set the audit fields from the student 
    	AuditEntity audit = new AuditEntity()
    	{
    		StudentId = student.Id,
    		OtherField = student.OtherField
    	}
    
    	//Update the student entity
    	student.StudentStatus = "Archive";
    	
    	//Save both records
    	db.Entry(AuditEntity).State = EntityState.Added;
    	db.SaveChanges();
    
    	return Json(id);
    }

    The docs explain the same.

    https://docs.microsoft.com/en-us/ef/ef6/saving/change-tracking/entity-state

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, February 26, 2019 9:26 PM
  • User1120430333 posted

    You should only be dealing wit the ordinal object you got in context.

    var original_data = db.StudentRec.AsNoTracking().Where(P => P.ID == id).FirstOrDefault();
    
                StudentRec NewRecord = original_data;
                NewRecord.StudentStatus = "Archive";
    
                db.Entry(NewRecord).State = EntityState.Modified;
                db.SaveChanges();

    So you supposedly copied 'original' to 'new', but they are the same object, the 'original'. And then you changed data and  state on 'new' that is really the 'orig'. And based on the primary ID of the object in 'new' that came from 'orig', it updated by ID the data table record in the database the 'original' data in the table record.

    Do you see what I am saying? The new and orig object have the same primary-key property that points back to the primacy-key ID of the record setting in the database table, which is the original data in the table record that  is being updated by primary-key ID.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, February 26, 2019 9:36 PM
  • User1901201124 posted

    I don't need to save both records thought.

    What i need to do is be able to call the method

    public void CreateAuditTrail(AuditActionType Action, int KeyFieldID, Object OldObject, Object NewObject)

    Which will take the OldObject and newObject and save the info into the Audit table. That is why i was trying to create 2 objects, 1 that had all the data of the old one and then another with all the data except one updated field.

    Tuesday, February 26, 2019 10:38 PM
  • User1901201124 posted

    Yeah its what i figured after i looked in the audit db table where i was saving both object data to. They were the same.

    Anyway to get the original object data "Student" and a new object data "Student" with the updated field?

    Tuesday, February 26, 2019 10:39 PM
  • User1901201124 posted

    I was able to accomplish what I wanted to do.

    But i had to create a new object and all all the fields of the old object. 

    Is there a better way than this? Doesn't seem efficient. Thanks

                var original_data = db.Student.AsNoTracking().Where(P => P.ID == id).FirstOrDefault();
                
    
                Student audit = new TaskAuthorizationOCCB()
                {
                    ID = id,
                    field_name = original_data.field_name,
                    ...etc... for all the fields in the table for this object
                };
    
                Student newObj = original_data;
                newObj.Status= "Archived";
                db.Entry(newObj).State = EntityState.Modified;
                db.SaveChanges();
    
                Audit history = new Audit();
                history.CreateAuditTrail(AuditActionType.Update, id, audit, newObj);
    
                return Json(id);

    Tuesday, February 26, 2019 11:06 PM
  • User475983607 posted

    Is there a better way than this? Doesn't seem efficient. Thanks

    Agreed but you have no choice due to the CreateAuditTrail method.  Perhaps refactor the CreateAuditTrail method.

    Tuesday, February 26, 2019 11:18 PM
  • User1901201124 posted

    Thanks for the help guys. I'll mark this question answered for now :)

    Wednesday, February 27, 2019 1:42 PM