0

I am having issues with updating the relation between two entities when editing one of them. Please note that I am using Entity Framework 4.0.

Very basically, a Category needs to belong to a Department (one Department to many Categories).

I implemented the following directly into the Category model:

public void Save()
{
    using (var db = new MyDatabase())
    {
        if (this.id > 0)
        {
            db.Categories.Attach(this);
            db.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
        }
        else
        {
            db.Categories.AddObject(this);
        }

        db.SaveChanges();
    }
}

public int DepartmentID
{
    get
    {
        if (this.DepartmentReference.EntityKey == null) return 0;
        else return (int)this.DepartmentReference
            .EntityKey.EntityKeyValues[0].Value;
    }
    set
    {
        this.DepartmentReference.EntityKey
           = new EntityKey("MyDatabase.Departments", "Id", value);
    }
}

Creating an object works without issue, it's only when I try to save an edited item that the issue occurs (so the issue lies within the if (this.id > 0) block).

I am aware that EntityState.Modified only applies to scalar values. The above snippet is a slightly older version. I have already tried to fix it in numerous ways, but none of these have solved the problem.

I found numerous solutions on Stackoverflow, but none of them worked. See below for snippets of my previous attempts.

I checked the values in debug, the current item's Department and DepartmentID fields correctly hold the changed value. Before the attaching, after the attaching, all the way through. But Entity Framework is ignoring these changes, while still correctly doing the scalar value adjustments.

What am I missing? If anyone could point me in the right direction?

The things I tried include:

//First try
if (this.id > 0)
{
    var department = db.Departments.Single(x => x.Id == this.DepartmentID);

    db.Categories.Attach(this);

    this.Department = department;

    db.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
}

//Second try
if (this.id > 0)
{
    db.Categories.Attach(this);
    db.Departments.Attach(this.Department);

    db.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
}

//Third try
if (this.id > 0)
{
    var department = db.Departments.Single(x => x.Id == this.DepartmentID);

    db.Categories.Attach(this);

    this.DepartmentID = department.Id;

    db.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
}

//Fourth try
if (this.id > 0)
{
    var departmentID = this.DepartmentID;

    db.Categories.Attach(this);

    this.Department = db.Departments.Single(x => x.Id == departmentID);

    db.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
}

Update

As requested, here's how the .Save() method is being called. Please note that the actual web form has been build using TextBoxFor() etc. so the modelbinding is okay. This exact same method is also used for the creation of the categories, which does work as intended.

    public JsonResult SaveCategory(Category category)
    {
        try
        {
            category.Save();

            return Json(category.toJson(), JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            return Json("ERROR", JsonRequestBehavior.AllowGet);
        }
    }
Martin Schmelzer
  • 23,283
  • 6
  • 73
  • 98
Flater
  • 12,908
  • 4
  • 39
  • 62
  • 1
    Would you please share the code that calls the Save() method? – Adel Khayata Aug 21 '13 at 11:57
  • It's nothing more than model-binding (via MVC), then calling Save(). But I'll add it for clarity. Update: I added it. – Flater Aug 21 '13 at 12:07
  • They way you are doing this can sometimes be tricky, see if this helps you: http://stackoverflow.com/questions/15177372/entity-framework-modify-detached-object – Mike C. Aug 21 '13 at 12:24
  • If I understand the question you referred to, that's about scalar properties not updating correctly. Scalars are okay, it's only the references to other entities that do not update. As I understand it, the scalars are already being handled by the `EntityState.Modified` setting. – Flater Aug 21 '13 at 12:33
  • I fixed it. See my answer below. – Flater Aug 21 '13 at 12:44

2 Answers2

0

You have to call db.SaveChanges() after you modify the entities.

Arnab Chakraborty
  • 7,442
  • 9
  • 46
  • 69
  • It's in there, but only after the `if else` block. I didn't include it in the block since it needs to be called regardless of Create or Update. – Flater Aug 21 '13 at 12:06
  • Can you add the Department and Category schemas. – Arnab Chakraborty Aug 21 '13 at 12:14
  • They are created by Entity Framework, I'm using a model first approach ('Generate database from model'). The snippets you see are part of a partial `Category` class I created to extend the entity. Everything except what I added is generated by EF. What is it syou specifically want to know about the entities? **Edit:** This is not a unique issue. All similar relations in the data model have the same issue. I assume there's some feature of EF I'm not using properly, since I've used basically the same Save function everywhere? – Flater Aug 21 '13 at 12:17
  • I fixed it. See my answer below. – Flater Aug 21 '13 at 12:45
0

I managed to find the issue. This was not an easy one.

I noticed that most of my relations created a Scalar value to the 'child' entity. (E.g. Category shoud have automatically received a DepartmentID scalar value). But this was not the case.

Here's the issue: if you create the association in EF, you get a window asking you to choose which two entities you want to associate. The child (Category, one) needs to be in the right field, while the parent (Department, many) needs to be on the left. The menu allows you to place them either side, there is nothing preventing you from doing this. But only if you enter the data one <-> many you will get the scalar value added. Not when you put it like many <-> one> even though that should be literally the same thing.

Am I right in stating that this is a bug?

My original snippet, which only does the .Attach() and EntityState.Modified now works as expected.

I can only mark this answer as correct in 2 days, but you can consider this question as closed.

Flater
  • 12,908
  • 4
  • 39
  • 62