5

I am learning ASP.NET MVC. I am following one of the basic tutorials on asp.net. Since I do not always follow the tutorials to the letter, I decided to use a GUID as the identity column instead of an integer. Everything was working fine until I got up to the point of adding a new record to the database through the MVC application. When I added the new record, it inserted a blank GUID instead of a generated one. Here is the segment of code-behind that handles the insertion:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "id")]Movie movieToCreate)
{
    try
    {
        _entities.AddToMovieSet(movieToCreate);
        _entities.SaveChanges();

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

The [Bind(Exclude = "id")] line 'ignores' the ID column, since it is autogenerated. In the tutorial, the ID is auto-incremented but I think that is because it is an integer. I tried adding a line to this method:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "id")]Movie movieToCreate)
{
    try
    {
        movieToCreate.id = Guid.NewGuid();
        _entities.AddToMovieSet(movieToCreate);
        _entities.SaveChanges();

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

But the id is still an empty GUID. Can anyone provide me with some information on why this is and perhaps how to resolve it?

3
  • Apparently removing the [Bind(Exclude)] and keeping the Guid.NewGuid() fixes this issue. I would still like to know why the ID is auto incremented but the GUID is not auto generated. Commented Aug 19, 2009 at 19:58
  • Both values are generated on the server. But the EF only sees the int because the SQL Server provider returns generated ints from the server, but not generated IDs. If you disposed the context and re-queried, you'd see both. Commented Aug 20, 2009 at 1:57
  • ...but not generated IDs. -> ...but not generated GUIDs. Commented Aug 20, 2009 at 1:58

4 Answers 4

6

You could use a custom ModelBinder. I learned about those over here.

public class MyClassBinder : DefaultModelBinder {
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) {
        var model = (Movie)base.CreateModel(controllerContext, bindingContext, modelType);
        model.id = Guid.NewGuid();
        return model;
    }
}

And your action controller would be:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(Movie movieToCreate) {
    // movie should have a new guid in the id
    _entities.AddToMovieSet(movieToCreate);
    _entities.SaveChanges();
}

And you would need to register the binder in Global.asax:

protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.Add(typeof(Movie), new MyClassBinder());
}
Sign up to request clarification or add additional context in comments.

3 Comments

Will I create this binder inside of its own file? If so, where should this be placed? In the same directory as my controllers? Thanks for the information and link!
I put my custom binders in a folder called Binders in the Models folder of my MVC Application.
I generally create an Extensions folder in my project and put stuff like that and HtmlHelper extensions in there.
1

The SQL Server EF provider in .NET 3.5 SP1 cannot retrieve server-generated GUIDs, since archaic versions of SQL Server couldn't support that. So you need to generate the GUID client-side, until this limitation is fixed.

You can do this in a model binder, as swilliams suggests, but IMHO binders should only bind data in the request. So I do it on my model tier. But either way will work.

3 Comments

Could you elaborate on your method? As I am learning I would like to know all the options I have available to me. Thanks!
Simple, really. I set the ID in code (with Guid.NewGuid()) before calling SaveChanges() when inserting a new record. All of this is done inside a model assembly which is separate from the assembly containing controllers and views.
So basically what I did, by removing the [Bind(Execute)] from the Movie parameter?
1

What is the type of ID field in SQL database? Is it uniqueidentifier? If not, change it to uniqueidentifier and make it autogenerated. Check out this article.

1 Comment

He has already done that; read the question carefully. The SQL Server provider for the EF won't forward the autogenerated GUIDs to the client.
0

You could as well update your get Create Action as follow and give it the new guid at this point. Then it would be automatically transferred to the post action. The the all code would look like that :

public ActionResult Create()
{
   Movie movietocreate = new Movie();

   movietocreate.id = Guid.NewGuid();  //you set the new guid here

   return View(movietocreate);   
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Movie movieToCreate)
{
    try
    {
        _entities.AddToMovieSet(movieToCreate);
        _entities.SaveChanges();

        return RedirectToAction("Index");
    }
    catch
    {
            return View();
    }
}

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.