6
votes

I am tired of fixing this error but nothing is working.

Here is the error:

System.InvalidOperationException: Nullable object must have a value.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Nullable1.get_Value() at Finance.Calculator.Presentation.Admin.Areas.HDGS.Controllers.TransactionController.Edit(Int64 TransactionId, String returnURL) in d:\BuildAgent2\work\83d988abf03ace44\Code\Presentation\Finance.Calculator.Presentation.Admin\Areas\HDGS\Controllers\TransactionController.cs:line 44 at lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.b__14() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList1 filters, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)

Here is my Code:

public ViewResult Edit(string TId, string returnURL)
    {
        long tid = !string.IsNullOrEmpty(TId) ? Convert.ToInt64(TId) : Convert.ToInt64(Request.QueryString["TId"].ToString());
        var TransactionItem = db.HDGSAccTransaction.SingleOrDefault(t => t.TransactionID.Equals(tid));
        TransactionVM oTrns = null;
        if (!string.IsNullOrEmpty(returnURL))
        {
            TempData["ReturnUrl"] = returnURL;
        }
        if (TransactionItem != null)
        {
            oTrns = new TransactionVM
            {
                TRef = TransactionItem.dimTransaction.TRef,
                Yr = TransactionItem.Yr,
                IcV = (decimal)TransactionItem.IcV,
                OFv = (decimal)TransactionItem.OFv,
                OCBv = (decimal)TransactionItem.OCBv,
                OOBv = (decimal)TransactionItem.OOBv,
                OInv = (decimal)TransactionItem.OInv
            };
        }

        return View(oTrns);
    }

Please Note: This code runs fine in the development environment from Visual Studio but not on the servers when it is deployed.

3
what line does it error on? Just dont throw code at us, try to point stuff out to help utilise our time - Valamas
What is the type of TransactionItem.IcV? if it's decimal? use GetValueOrDefault instead of cast (same for all others props). - Alessandro D'Andria
@ Valamas - AUS: Thanks. But this works fine in my dev machine and not on the server. That's why I don't have any hints - Todd Wilson
@ToddWilson: i guess that the reason why you get it only on your server is that the variables have different values there. I assume that you have a Nullable<T> which is null. Then the explicit cast to decimal throws the exception. - Tim Schmelter

3 Answers

10
votes

I guess the reason why it's only working on your development environment is that the variables always have a value there and on your server the nullables are null.

If a Nullable<T> is null you cannot cast it explicitly to the value type because you get your exception "Nullable object must have a value". (Demo)

So don't cast it. What value do you want to use instead of null, you could use decimal.MinValue:

// ...
IcV = TransactionItem.IcV.HasValue ? TransactionItem.IcV.Value : decimal.MinValue,
// ...

For what it's worth, here is an extension method:

public static T SafeCast<T>(this Nullable<T> t, T defaultValue = default(T)) where T : struct
{
    return t.HasValue ? t.Value : defaultValue;
}

Then you can from now on use this:

IcV = TransactionItem.IcV.SafeCast(decimal.MinValue),
0
votes

I just battled with a simular problem, where the database model, generated in entity framework, differed from the domain model. The difference was namely in the nullable property of an integer value.

To solve this, the convention of nullable had to be alligned equally for both the database model and the domain model.

0
votes

I wanted to get a Nullable SQL Server Money datatype to show up in read only display as 2 decimal places: I took the model coming in (c.AmountAgreedOn) and right there in the view inside the rows of td's I put this:

   @{
    string value = "";
    decimal? decimalValue = c.AmountAgreedOn;
    if (decimalValue.HasValue)
    {
         value = ((decimal)(decimalValue)).ToString("0.00");
        <td align="center">@value</td>
    }
    else
    {
               <td align="center">@value</td>
    }
}

So I got a "" for display value if no money amount yet entered.

then. . . . . when opening this to edit or add value in the model.cs class I put this above the "AmountAgreedOn":

[DisplayFormat(ApplyFormatInEditMode = false, DataFormatString = "{0:c}")]
public Nullable<decimal> AmountAgreedOn { get; set; }

If you want dollar sign to show ( didn't because it messed with saving decimal type), change ApplyFormatInEditMode to "true".

Not pretty but I couldn't figure out any other way. I just don't get the mad scientist stuff.