Система.Исключение InvalidOperationException: обнуляемый объект должен иметь value.ASP.NET MVC

#c# #asp.net-mvc #linq #nullable

#c# #asp.net-mvc #linq #обнуляемый

Вопрос:

Я устал исправлять эту ошибку, но ничего не работает.

Вот ошибка:

Система.Исключение InvalidOperationException: объект с нулевым значением должен иметь значение.
в системе.ThrowHelper.Исключение ThrowInvalidOperationException (ресурс ExceptionResource) в системе.Обнуляемый 1.get_Value() at
Finance.Calculator.Presentation.Admin.Areas.HDGS.Controllers.TransactionController.Edit(Int64
TransactionId, String returnURL) in
d:BuildAgent2work83d988abf03ace44CodePresentationFinance.Calculator.Presentation.AdminAreasHDGSControllersTransactionController.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, IDictionary
2 параметра) в System.Web.Mvc.ControllerActionInvoker.Метод InvokeActionMethod(ControllerContext ControllerContext, ActionDescriptor actionDescriptor, IDictionary 2
parameters) at
System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter
filter, ActionExecutingContext preContext, Func
1 продолжение) в System.Web.Mvc.ControllerActionInvoker.<> c__DisplayClass15.<>c__DisplayClass17.b__14() в System.Web.Mvc.ControllerActionInvoker.invokeactionmethod с фильтрами (ControllerContext ControllerContext, IList 1 filters, ActionDescriptor actionDescriptor,
IDictionary
2 параметра) в System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext ControllerContext, строковое имя действия)

Вот мой код:

 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);
    }
  

Пожалуйста, обратите внимание: Этот код отлично выполняется в среде разработки из Visual Studio, но не на серверах, когда он развернут.

Комментарии:

1. в какой строке он выдает ошибку? Просто не бросайте в нас код, попробуйте указать на вещи, которые помогут использовать наше время

2. Какой тип TransactionItem.IcV ? если он decimal? используется GetValueOrDefault вместо приведения (то же самое для всех остальных реквизитов).

3. @ Valamas — AUS: Спасибо. Но это отлично работает на моем компьютере разработчика, а не на сервере. Вот почему у меня нет никаких подсказок

4. @ToddWilson: я предполагаю, что причина, по которой вы получаете это только на своем сервере, заключается в том, что переменные там имеют разные значения. Я предполагаю, что у вас есть, Nullable<T> который null . Затем явное преобразование в decimal генерирует исключение.

Ответ №1:

Я предполагаю, что причина, по которой он работает только в вашей среде разработки, заключается в том, что переменные всегда имеют значение там, а на вашем сервере значения с нулевым значением null .

Если a Nullable<T> есть null , вы не можете явно привести его к типу значения, потому что вы получаете исключение «Объект с нулевым значением должен иметь значение». (Демонстрационный вариант)

Поэтому не приводите его. Какое значение вы хотите использовать вместо null , вы могли бы использовать decimal.MinValue :

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

Как бы то ни было, вот метод расширения:

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

Тогда с этого момента вы можете использовать это:

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

Комментарии:

1. Спасибо, Тим. Позвольте мне попробовать это.

2. Привет, Тим. Если вы видите мой код, существует условие, при котором TId не может быть найден в db.HDGSAccTransaction В этом случае я показываю сообщение о несуществовании этого TId и ссылку «Вернуться к предыдущему». Даже для этих транзакций я получаю эту ошибку.

3. @ToddWilson: я не вижу кода, в котором вы выводите сообщение. Однако я не понимаю, как if (TransactionItem != null) это связано с этим. Это просто проверяет, TransactionItem есть null ли это, а не если TransactionItem.IcV есть null (или другие обнуляемые свойства).

4. @ Tim: Это когда значение null viewModel object переходит в view и внутри него я проверяю, является ли model нулевым. Это часть представления. Это просто для того, чтобы вы знали, что я получаю ту же ошибку, даже если TransactionItem равно null

5. @ToddWilson: я не настолько знаком с MVC, поэтому я не знаю, что также может вызвать это в этом методе. TransactionID.Equals не должен вызывать, даже если TransactionID обнуляемое свойство, которое является null .

Ответ №2:

Я только что столкнулся с проблемой симуляции, когда модель базы данных, сгенерированная в entity framework, отличалась от модели домена. Разница заключалась именно в свойстве nullable для целочисленного значения.

Чтобы решить эту проблему, соглашение nullable должно было быть выровнено одинаково как для модели базы данных, так и для модели домена.

Ответ №3:

Я хотел получить обнуляемый тип данных SQL Server Money, который отображался бы на дисплее только для чтения в виде 2 знаков после запятой: я взял входящую модель (c.AmountAgreedOn) и прямо там, в представлении внутри строк td, я поместил это:

    @{
    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>
    }
}
  

Итак, я получил «» для отображаемого значения, если денежная сумма еще не введена.

затем . . . . . при открытии этого для редактирования или добавления значения в классе model.cs я помещаю это выше «AmountAgreedOn»:

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

Если вы хотите, чтобы отображался знак доллара (не отображался, потому что это мешало сохранению десятичного типа), измените ApplyFormatInEditMode на «true».

Не очень, но я не смог придумать другого способа. Я просто не понимаю, что такое mad scientist.