4

How can I use strongly-typed Controllers with EntityObjects?

My failures...

First I tried this:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    db.SaveChanges();
    return RedirectToAction("Index");
}

This failed to actually save any changes to the database. So, I tried to attach the model to my ObjectContext:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    db.Attach(Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

This failed because "an object with a null EntityKey value cannot be attached to an object context." So, I tried to assign the EntityKey:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    Model.EntityKey = (from Department d in db.Department
                       where d.Id == id
                       select d).FirstOrDefault().EntityKey;
    db.Attach(Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

This failed because "an object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."

How is this supposed to work?

1

4 Answers 4

3

The thing is, what you have as your input is not a complete model object with changed properites - it is just a "start" of new one, with all the properties that you want to overwrite on an already existing entity. You don't post any of the ID properties,

This looks a little verbose, but it's the best I've found, so it is how I do it in my projects (ajusted to your class names, with whatever was missing made up...):

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    var dbDepartment = (from Department d in db.Department
                        where d.Id == id
                        select d).FirstOrDefault() as Department

    dbDepartment.Name = Model.Name;
    dbDepartment.Color = Model.Color;
    // etc, assigning values manually...

    try
    {
        db.SaveChanges();
    }
    catch (Exception ex)
    {
        // oops...
    }
    return RedirectToAction("Index");
}
Sign up to request clarification or add additional context in comments.

2 Comments

That doesn't really look like a step forward ;).
Not if what matters is beautiful code. This isn't beautiful... But it works, so compared with code that doesn't, I must say it is a step forward! ;)
1

Try db.AttachTo() instead of db.Attach()

As described here

"Call AttachTo on ObjectContext to attach the object to a specific entity set in the object context. Also do this if the object has a null (Nothing in Visual Basic) EntityKey value."

Edit: actually, you may need to call ApplyPropertyChanges() in this case.

Edit 2: You can build an entity key for your object with code like the following:

public EntityKey GetEntityKey(string entitySetName, object keyValue)
{
  IEnumerable<KeyValuePair<string, object>> entityKeyValues =
    new[]
    {
      new KeyValuePair<string, object>("Id", keyValue)
    };

  var key = new EntityKey(string.Concat("YOUR_OBJECT_CONTEXT_NAME.", entitySetName), entityKeyValues);
  return key;
}

And then you'd call this with something like this for entity keys based on a single database column called 'Id':

var entityKey = GetEntityKey("Customer", 23);

I use a similar method in my own EF code except with a Generic type argument to avoid having to use a string for the entity class name.

4 Comments

This works: Model.EntityKey = ...; db.ApplyPropertyChanges("Department", Model); db.SaveChanges();
But, is there any way to not have to perform a database query to determine the EntityKey?
I've updated the other question: stackoverflow.com/questions/898260/…
1

How about this

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, Department dept)
{
    Department tmp = new Department()
    {
        Id = dept.Id
    };
    try
    {
        db.Departments.Attach(dept, tmp);
        db.Save();
    }
}

Maybe the tmp-part can be exchanged for a call to UpdateModel after the Attach part, but I'm not sure.

Edit: Just looked up the documentation on Attach(Entity e, Entity original) and it does indeed replace original with e (or update original accordingly or w/e).

Comments

0

I don not recommend to use a POCO into you MVC application. You should use a DTO or a model.

Maybe you should retrieve an object by id before and then replace the values you supplied by arguments to edit method and then save changes. You get an error because you didn't deattach the model in the first place.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model) {
var entity=from m in db.Models where m.Id == Model.id select m;
Model entityAttached=entity.FirstOrDefault();
//replace all the new values in you object
db.SaveChanges();
}

or deattach object when you get it by id and attach it back when you want to save the new values in edit method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.