1

I am using the WebAPI in MVC4. I have a simple form which submits data to the API via a PUT request. The data arrives and is serialized fine and everything looks wonderful, except that anywhere there is a foreign key is not getting updated. And yes, the foreign key exists.

I have the following classes:

public class TriageRecord
{
    [Key]
    public Int64 PKEY { get; set; }
    public DateTime DateAdded { get; set; }
    public DateTime DateUpdated { get; set; }
    public Int64? RecordSource_Id { get; set; }  
    public Int64? AssignedVolunteer_Id { get; set; }  
    public string FacebookID { get; set; }
    public Int64? VANID { get; set; }
    public Int64? NationBuilderID { get; set; }
    public DateTime? DateVanSubmitted { get; set; }
    public Int64? FollowUpLevel_Id { get; set; } 
    public bool? Complete { get; set; }


    public string First { get; set; }
    public string Mid { get; set; }
    public string Last { get; set; }
    public string Email { get; set; }
    public string Address1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip5 { get; set; }


    public string HomePhone { get; set; }
    public string CellPhone { get; set; }

    public Int32? EmployeeStatus { get; set; }
    public string StoreNumber { get; set; }
    public virtual WorkArea WorkArea { get; set; }   //put your focus here
    public virtual Department Department { get; set; }
    public virtual Shift Shift { get; set; }


   }

Here is the WorkArea class which I am updating via my form.

public class WorkArea
{
    [Key]
    public Int64 Id { get; set; }
    [StringLength(200)]
    public string WorkAreaName { get; set; }
}

Here is the JSON I am posting which arrives very nicely to my API Controller:

   var saveRecord = function() {
            var record = {
                "PKEY": $("#PKEY").val(),
                "DateAdded": $("#DateAdded").val(),
                "DateUpdated": "@DateTime.Now.ToString()",
                "First": $("#First").val(),
                "Mid": $("#Mid").val(),
                "Last": $("#Last").val(),
                "RecordSource_Id": $("#RecordSource_Id").val(),
                "AssignedVolunteer_Id": $("#AssignedVolunteer_Id").val(),
                "FacebookID": $("#FacebookID").val(),
                "VANID": $("#VANID").val(),
                "NationBuilderID": $("#NationBuilderID").val(),
                "DateVanSubmitted": Date.now(),
                "FollowUpLevel_Id": $("#FollowUpLevel_Id").val(),
                "Complete": $("#Complete").val(),
                "Email": $("#Email").val(),
                "Address1": $("#Address1").val(),
                "City": $("#City").val(),
                "State": $("#State").val(),
                "Zip5": $("#Zip5").val(),
                "HomePhone": $("#HomePhone").val(),
                "CellPhone": $("#CellPhone").val(),
                "EmployeeStatus": $("#EmployeeStatus").val(),
                "StoreNumber": $("#StoreNumber").val(),
                "WorkArea": {
                    "Id": 1,
                    "WorkAreaName": "GM"
                },
                "Department": $("#Department").val(),
                "Shift": $("#Shift").val()                       
            };

It is serialized and it arrives to my controller where I can see when I set my breakpoint that the WorkArea (Models.WorkArea) is populated with Id = 1 & WorkAreaName = "GM"

So this is my controller:

  public HttpResponseMessage PutTriageRecord(long id, TriageRecord triagerecord)
    {
        if (id == triagerecord.PKEY)  //breakpoint here shows triagerecord contains workarea values
        {                
            db.Entry(triagerecord).State = EntityState.Modified;                
            try
            {                    
            db.SaveChanges();  //changes get saved for everything (ie, first name) but not workarea...
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            return Request.CreateResponse(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }

Everything is updated in my TriageRecord except for WorkArea... Why?

Update: NOT WORKING. This is what I added to my controller... it just keeps creating a ton of entires in the WorkAreas table.

  public HttpResponseMessage PutTriageRecord(long id, TriageRecord triagerecord)
    {
        if (id == triagerecord.PKEY)  //breakpoint here shows triagerecord contains workarea values
        {                
            db.Entry(triagerecord).State = EntityState.Modified;                
            try
            {      
                db.TriageRecords.Attach(triagerecord);   //attach
                db.Entry(triagerecord.WorkArea).State = EntityState.Added;   //add           
            db.SaveChanges();  //WORKS!
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            return Request.CreateResponse(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }
Ray Suelzer
  • 4,026
  • 5
  • 39
  • 55
  • Please focus the question. What does JSON or WebAPI have to do with Foreign Keys? I suspect the question is about a particular DAL/ORM .. –  Dec 10 '12 at 00:36
  • I'm posting via a PUT in Json format to Web-API. It's likely someone else has had this problem before. – Ray Suelzer Dec 10 '12 at 00:39
  • JSON and PUT are immaterial once the data is received/decoded on the server. They are merely the means to the problem, but not the problem itself. –  Dec 10 '12 at 00:43
  • Then can you suggest a new title for me? The question itself makes sense correct? I'm getting the data to the server, but db.SaveChanges() is not saving the foreign key constraint – Ray Suelzer Dec 10 '12 at 00:47
  • Sounds like an EF issue, perhaps similar to this question: http://stackoverflow.com/questions/3220543/entity-framework-saving-child-entities-on-update – Jeff Ogata Dec 10 '12 at 00:49
  • @RaySülzer So now we are getting somewhere! "EF foreign key (or entity?) not cascading/updating" sounds like a better synopsis. –  Dec 10 '12 at 00:51
  • Updated... Hopefully someone can answer this. I've been looking around for something similar. – Ray Suelzer Dec 10 '12 at 01:08
  • http://stackoverflow.com/questions/8498501/updating-foreign-key-entities-in-entity-framework-4-1 Same question that was never answered. Could be a bug? – Ray Suelzer Dec 10 '12 at 01:17

1 Answers1

1

You need to call Attach and set the state of the child objects to Added. It doesn't have anything to do with WebApi, this is how EF works when you are working with detached objects (e.g. when you send them out to client side and back). The db context track's the changes so it won't know what has been added modified automatically when you work with detached objects.

"If you don't call Attach the children stay detached until SaveChanges is called where EF will assume that they are new entities (because they are not attached to the context) and set their state to Added. Then they will be inserted into the database."

EF 4.3 CF does not update relationships when saving changes

Community
  • 1
  • 1
  • 1
    It would sit before your db.SaveChanges() in the PutTriageRecord method. You will need to look through the child objects. Just remember WebApi is only a transportation tool, gets data from A to B, then back from B to A. Visual Studio will help you out and create basic crud but this does not extend EF features. That's all up to you. –  Dec 10 '12 at 01:46
  • Actually, the code changes I made are just adding a ton of entries to the WorkArea table instead of updating the foreign key relationship... Ideas? – Ray Suelzer Dec 10 '12 at 02:03
  • Use the modified state instead of Added. You will need to do a check to see if the object has an ID, then it exists so set to Modified, if it doesn't, only then set it to Added. –  Dec 10 '12 at 02:52
  • Follow that instruction and it still doesn't save. I think this is a known issue since I have found other people on the web with the same problem and no answer. I just ended up ditching EF and going with direct SQL commands. Much faster. – Ray Suelzer Dec 10 '12 at 19:15