Link to home
Start Free TrialLog in
Avatar of homeshopper
homeshopperFlag for United Kingdom of Great Britain and Northern Ireland

asked on

An optional parameter must be a reference type

When I create a new record, I get the following error:
For clarity, I have listed the code I have so far.
Thanks in advance.
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Create(Nop.Web.Models.User.User, Int32)' in 'Nop.Web.Controllers.MyUsersController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

Open in new window

MyUsersController.cs
public class MyUsersController : Controller
    {
        private mvcDBContext db = new mvcDBContext();
        // GET: /MyUsers/
        public ViewResult Index()
        {
            return View(db.Users.ToList());
        }
        // POST: /MyUsers/Create
        [HttpPost]
        public ActionResult Create(User user, int id)
        {
            if (ModelState.IsValid)
            {
                db.Users.Add(user);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(user);
        }

Open in new window

User.cs
public class User
    {
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    public class mvcDBContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    }

Open in new window

Create.cshtml
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>User</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

Open in new window

Avatar of draek
draek

The parameter 'id' from the class 'MyUserController' from the function 'ActionResult Create(User user, int id)' is not a nullable type (Int32 is a value type). You can use as a parameter a reference type(reference types are Strings,arrays,classes and delegates) or a nullable type.
Avatar of homeshopper

ASKER

Thank you for your response.
You are correct in what you say,
but 'How can I use as a parameter a reference type'
UserId is int and the primary key (does not accept Null).
Thanks in advance.
A string is a reference type so you can use that and pass it as int.
I have now tried the following:
[HttpPost]
        public ActionResult Create(User user, string id)
        {

Open in new window

I get new error as below:
Thanks in advance for the help.
Exception Details: System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'UserId', table 'mvcDBs.dbo.Users'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Source Error: 
Line 25:             {
Line 26:                 db.Users.Add(user);
Line 27:                 db.SaveChanges();
Line 28:                 return RedirectToAction("Index");
Line 29:             }

Open in new window

You need to allow nulls in your table or configure your data source to not insert anything in this column and let server generate the value.
If I try [HttpPost]
        public ActionResult Create(User user)
        {
I get same error.
If I change public int UserId { get; set; } to public string UserId { get; set; }
get validation errors.
If I take out UserId, still get errors.
I am not sure what to try next.
I probably do not fully understand your response.
Thanks in advance.
You can allow nulls on the table by using management studio.
Right click on the table and choose design, and check the box under the 'Allow Nulls' next to the column name you want to allow nulls on.
Yes, in this instance it would work if UserId was changed to type string & allow nulls;
but this is a prelude to building a more complex form connected to an existing table where
the UserId is (PK,int, not null).
How can this be done programmatically?
[HttpPost]
        public ActionResult Create(User user)
        {
            if (ModelState.IsValid)
            {
                db.Users.Add(user);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(user);
        }

Open in new window


In the User class you have all those informations (id, firstname, lastname) so when you pass the class to the create function all those informations will be taken and inserted in db.Why you need the parameter id?
Thankyou, I understand what you say.
So now have the following, I have taken out UserId as suggested.
public class User
    {
        //public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
This now gives, yet another, different error:

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmEntityType: : EntityType 'User' has no key defined. Define the key for this EntityType.
\tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'Users' is based on type 'User' that has no keys defined.
Source Error:
Line 24:             if (ModelState.IsValid)
Line 25:             {
Line 26:                 db.Users.Add(user);
Line 27:                 db.SaveChanges();
Line 28:                 return RedirectToAction("Index");
Source File: C:\Users\Ian\aaaNopComProjects\webApp-AltSourceFinal\Presentation\Nop.Web\Controllers\MyUsersController.cs    Line: 26
No you don't. I said why you need to add that id parameter on the function create?
Use like this:

public class User
    {
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

[HttpPost]
        public ActionResult Create(User user) //only here you take out 
        {
            if (ModelState.IsValid)
            {
                db.Users.Add(user);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(user);
        }

Open in new window

I had already tried that, it was the start of the ever increasing circle of errors.
The error given is below:
Cannot insert the value NULL into column 'UserId', table 'mvcDBs.dbo.Users'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Have you set UserId as primary in your table?
I have just doubled checked.
Yes, UserId is set to Primary key.
Avatar of kaufmed
Why not simply set the parameter as having a default value?

public ActionResult Create(User user, int id = -1)

Open in new window

Thank you for the suggestion, I thought it had been cracked, but sadly not.
I even stried id= 0 & id=1.
Very strange, still gives 'cannot insert the value null into column UserId'
OK, my suggestion is to solve the original error regarding the null value dictionary (yadda yadda). This is a new error, and it is related to the state of your model. What was the id parameter supposed to represent? Is it the UserId? If so, then why do you have a UserId on your model? Why not just have one rather than two?
Yes, the column or field name is UserId.
So now in model:
public class User
    {
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
and in Controller:
public class MyUsersController : Controller
    {
        private mvcDBContext db = new mvcDBContext();
        // GET: /MyUsers/
        public ViewResult Index()
        {
            return View(db.Users.ToList());
        }
        // POST: /MyUsers/Create
        [HttpPost]
        public ActionResult Create(User user, int UserId = 0)
        {
            if (ModelState.IsValid)
            {             
                db.Users.Add(user);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(user);
        }
        // GET: /MyUsers/Create
        public ActionResult Create()
        {
            return View();
        }
        // GET: /MyUsers/Edit/5
        public ActionResult Edit(int id)
        {
            User user = db.Users.Find(id);
            return View(user);
        }
        // POST: /MyUsers/Edit/5
        [HttpPost]
        public ActionResult Edit(User user)
        {
            if (ModelState.IsValid)
            {
                db.Entry(user).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(user);
        }

Open in new window

The Edit action works fine, just Create new causes error.
Thanks in advance.
What does the HTML look like--specifically the <form>?
The code for Create.cshtml is below:
@model Nop.Web.Models.User.User
@{
    ViewBag.Title = "Create";
    Layout = "~/Themes/CorpWear2/Views/Shared/_ColumnsThree.cshtml";
}
<br /><br />
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>User</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Open in new window

I do not see where you have either User.UserId or id present in that HTML. How were you intending they be populated (for when they get sent to the server)?
I have now added: @Html.HiddenFor(model => model.UserId) to Create.cshtml
and in the controller:
[HttpPost]
        public ActionResult Create(User user, int UserId = 1)
It does not crash, but also does not update or create a new record.
Can we try this:  I think that the second UserId parameter is extraneous--you've already got a UserId parameter on your model class. Can we change the controller to:

[HttpPost]
public ActionResult Create(User user)

Open in new window


The .cshtml bit should be fine as-is.

Now, set a breakpoint on the first line of your Create action. Run your project and click the button. Is the breakpoint hit? If so, mouse over the user variable. Is the UserId set?
Thank you for your response, sorry not to have replied earlier.
Ok, I put a break at public ActionResult Create(User user)
When the button is clicked it does not hit the break point.
When mousing over User,
FirstName = aa
LastName = bb
UserId      = 0
Thanks in advance for any help.
sorry, meant to say when the break point is hit.
I have pressed F11 several times and UserId = 0
untill it executes db.SaveChanges();
The error message is then displayed:
Cannot insert the value NULL into column 'UserId', table 'mvcDBs.dbo.Users';
column does not allow nulls. INSERT fails.The statement has been terminated.
Not sure what to try next.
ASKER CERTIFIED SOLUTION
Avatar of homeshopper
homeshopper
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I found the solution myself, but would like to thank the experts for their help.