Исключение: Нулевое значение не может быть назначено члену с типом System.Int32, который является необнуляемым типом значения - PullRequest
1 голос
/ 28 марта 2011

Может кто-нибудь объяснить, почему это исключение происходит в следующем запросе LINQ:

        return (from c in dc.Classifications
                where c.Id == classificationId
                select new Classification()
                {
                    Description = c.Description,
                    ParentId = Convert.ToInt16(c.ParentId),
                }).Single<Classification>();

dc - это текст данных, Classification - это класс, содержащий свойство int ParentId. Столбец ParentId представляет собой пустое значение int из базы данных Sql Server. В случае, если поле ParentId в базе данных пусто, инструкция возвращает исключение InvalidOperationException.

Другими словами, почему приведенный выше запрос не выполняется и 'int y = Convert.ToInt16 (null);'
работать?

Ответы [ 3 ]

2 голосов
/ 28 марта 2011

Предполагая, что вы хотите иметь 0 как ParentId, когда он равен NULL в базе данных:

    return (from c in dc.Classifications
            where c.Id == classificationId
            select new Classification()
            {
                Description = c.Description,
                ParentId = Convert.ToInt16(c.ParentId ?? 0),
            }).Single<Classification>();

Мой ответ также предполагает, что Classifications.ParentId имеет тип Nullable<int> / int?и его значение равно null, если столбец равен NULL в базе данных.

Единственное, что я изменил, это часть ?? 0 в преобразовании.Он использует 0 в случае, если c.ParentId равен null и c.ParentId в противном случае.Смотри ??Оператор для получения дополнительной информации.

1 голос
/ 28 марта 2011

Если c.PartentId может быть null, то Convert.ToInt16(null) выдаст исключение.

Поскольку вы указываете, что Classification.ParentId является целым числом, есть ли причина, по которой вы используете Convert.ToInt16 длясделать это коротким вместо этого?Разве вы не хотите вместо этого ToInt32?В этом отношении, зачем вообще конвертировать?просто:

ParentId = c.ParentId ?? 0

... и просто придираться, технически вам не нужно указывать ваш тип в конце этого выражения Linq:

.Single<Classification>()

вы можетепропустите это, так как это определяется компилятором, и просто выполните:

.Single()

Обновление:

О, я вижу, извините, янеправильно прочитал ваш оригинальный вопрос.Вопрос действительно в том, почему:

int y = Convert.ToInt16(null);

работает, а то же самое в выражении Linq2Sql вызывает исключение.

У меня нет отличного ответа на этот вопрос, кроме как наотметим, что хотя выражения выглядят одинаковыми в коде, они фактически обрабатываются двумя реализациями Linq для разных сетей.(Так же, как интерфейс может иметь различные реализации поддержки).

В случае:

int y = Convert.ToInt16(null);

Вы делаете прямой вызов Convert.ToInt16.Похоже, что это преобразует ноль в default<T>, где T - требуемый тип (поэтому он возвращает 0 в этом случае).

Однако при использовании в выражении Linq2Sql выражение и его проекция передаются Linq2Entitiesили Linq2Sql для обработки.Там может быть просто ошибка в этом материале где-то.Используется как базовый объект Linq2Objects (или как вы хотите его называть), на самом деле кажется, что он работает нормально:

[TestMethod] // test passes
public void TestLinqToObjects()
{
  var stuff = new List<int?>() { null };
  var y = (from x in stuff
           select Convert.ToInt32(x))
           .First();
  Assert.AreEqual(0, y);
}

Вышеприведенный «select» работает, однако размещение того же выражения Linq для коллекции Linq2Sql или EntityFrameworkзаставить другую реализацию процессора Linq обрабатывать выражение, и он может сделать что-то другое, пытаясь оптимизировать выражение или превратить часть из него в оператор SQL, или может просто иметь ошибки, которые другие реализации не могут.

Я знаю, что это на самом деле не решает вашу проблему, но может помочь объяснить ее?

0 голосов
/ 28 марта 2011

c.ParentId имеет тип int?

Ваш вызов Convert.ToInt16 прервется двумя способами; он завершается с ошибкой на нуле (как здесь) и происходит сбой, если ParentId больше short.MaxValue или меньше short.MinValue.

Почему этот звонок там? Убери это. Кроме того, замените Single<Classification>() на SingleOrDefault(), чтобы он мог возвращать ноль при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...