Solved

An optional parameter must be a reference type

Posted on 2014-10-01
28
1,579 Views
Last Modified: 2014-11-18
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

0
Comment
Question by:homeshopper
  • 16
  • 7
  • 5
28 Comments
 

Expert Comment

by:draek
ID: 40353990
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.
0
 

Author Comment

by:homeshopper
ID: 40354003
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.
0
 

Expert Comment

by:draek
ID: 40354008
A string is a reference type so you can use that and pass it as int.
0
 

Author Comment

by:homeshopper
ID: 40354030
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

0
 

Expert Comment

by:draek
ID: 40354052
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.
0
 

Author Comment

by:homeshopper
ID: 40354080
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.
0
 

Expert Comment

by:draek
ID: 40354087
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.
0
 

Author Comment

by:homeshopper
ID: 40354110
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?
0
 

Expert Comment

by:draek
ID: 40354124
[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?
0
 

Author Comment

by:homeshopper
ID: 40354187
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
0
 

Expert Comment

by:draek
ID: 40354202
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

0
 

Author Comment

by:homeshopper
ID: 40354213
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.
0
 

Expert Comment

by:draek
ID: 40354271
Have you set UserId as primary in your table?
0
 

Author Comment

by:homeshopper
ID: 40354280
I have just doubled checked.
Yes, UserId is set to Primary key.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40354329
Why not simply set the parameter as having a default value?

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

Open in new window

0
 

Author Comment

by:homeshopper
ID: 40354387
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'
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40354398
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?
0
 

Author Comment

by:homeshopper
ID: 40354477
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.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40354543
What does the HTML look like--specifically the <form>?
0
 

Author Comment

by:homeshopper
ID: 40354555
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

0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40354567
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)?
0
 

Author Comment

by:homeshopper
ID: 40354645
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.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40354812
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?
0
 

Author Comment

by:homeshopper
ID: 40358942
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.
0
 

Author Comment

by:homeshopper
ID: 40358944
sorry, meant to say when the break point is hit.
0
 

Author Comment

by:homeshopper
ID: 40359033
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.
0
 

Accepted Solution

by:
homeshopper earned 0 total points
ID: 40361160
I have now been able to get my solution to work.
I would like to thank the experts and their responses for the help.
Below for clarity and to help others, is the solution and code.
This time I started without a database and in the Web.Config
<connectionStrings>
    <add name="dBaseDBContext"   connectionString="Data Source=(local);Initial Catalog=dBase;User ID=sa;Password=xxxxxx;" providerName="System.Data.SqlClient"/>
</connectionStrings>

Open in new window

Next is Models.dBaseTable.dBaseTable.cs
This time I added [Key] before the first table field with Primary Key
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;

namespace Nop.Web.Models.dBaseTable
{
    public class dBaseTable
    {
        [Key]
        public int      dBaseId { get; set; }         
        public string FirstName { get; set; }
        public string LastName  { get; set; }
    }
    public class dBaseDBContext : DbContext
    {
        public DbSet<dBaseTable> dBaseTables { get; set; }
    }
}

Open in new window

Then finally,  to generate the dBaseController.cs
First, compile the code sofar, then using template to generate controller dBaseController.cs
The dBase database with table dBaseTables is created and when the solution is run
it enters records successfully.

Controllers.dBaseController.cs
Controller with read/write actions and views, using Entity Framework
dBaseTable (Nop.Web.Models.dBaseTable)
dBaseDBContext (Nop.Web.Models.dBaseTable)
Razor (CSHTML)
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Nop.Web.Models.dBaseTable;

namespace Nop.Web.Controllers
{ 
    public class dBaseController : Controller
    {
        private dBaseDBContext db = new dBaseDBContext();
        // GET: /dBase/
        public ViewResult Index()
        {
            return View(db.dBaseTables.ToList());
        }
        // GET: /dBase/Details/5
        public ViewResult Details(int id)
        {
            dBaseTable dbasetable = db.dBaseTables.Find(id);
            return View(dbasetable);
        }
        // GET: /dBase/Create
        public ActionResult Create()
        {
            return View();
        } 
        // POST: /dBase/Create
        [HttpPost]
        public ActionResult Create(dBaseTable dbasetable)
        {
            if (ModelState.IsValid)
            {
                db.dBaseTables.Add(dbasetable);
                db.SaveChanges();
                return RedirectToAction("Index");  
            }
            return View(dbasetable);
        }
        // GET: /dBase/Edit/5
        public ActionResult Edit(int id)
        {
            dBaseTable dbasetable = db.dBaseTables.Find(id);
            return View(dbasetable);
        }
        // POST: /dBase/Edit/5
        [HttpPost]
        public ActionResult Edit(dBaseTable dbasetable)
        {
            if (ModelState.IsValid)
            {
                db.Entry(dbasetable).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(dbasetable);
        }
        // GET: /dBase/Delete/5
        public ActionResult Delete(int id)
        {
            dBaseTable dbasetable = db.dBaseTables.Find(id);
            return View(dbasetable);
        }
        // POST: /dBase/Delete/5
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {            
            dBaseTable dbasetable = db.dBaseTables.Find(id);
            db.dBaseTables.Remove(dbasetable);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}

Open in new window

This generates the following Views:
Views.dBase.Index.cshtml
Views.dBase.Create.cshtml
Views.dBase.Details.cshtml
Views.dBase.Edit.cshtml
Views.dBase.Delete.cshtml
0
 

Author Closing Comment

by:homeshopper
ID: 40449358
I found the solution myself, but would like to thank the experts for their help.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
Today is the age of broadband.  More and more people are going this route determined to experience the web and it’s multitude of services as quickly and painlessly as possible. Coupled with the move to broadband, people are experiencing the web via …
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now