Разыменование возможной нулевой ссылки в запросе Entity Framework 6

0

Вопрос

У меня есть проект .NET 6 с включенными типами ссылок с возможностью обнуления (<Nullable>enable</Nullable>). У меня есть эта сущность EF:

public class PostFile {
  public Int32 UserId { get; set; }
  public Int32 PostId { get; set; }

  public virtual User? User { get; set; }
  public virtual Post? Post { get; set; }
}

Я добавил ? выше, чтобы предотвратить это недействительное предупреждение:

Non-nullable property '...' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Теперь у меня есть этот запрос LINQ Entity Framework 6:

var postFiles = context.postFiles.Where(x => x.User.Id == request.UserId);

... но я получаю следующее предупреждение:

Dereference of a possibly null reference.

... в этой части моего запроса:

x.User.Id == ...

Как я могу исправить это предупреждение?

4

Лучший ответ

2

Я думаю, ты имеешь в виду что-то вроде:

public class PostFile {
    public Int32 UserId{ get; set; }
    public Int32 PostId { get; set; }

    public virtual User? User { get; set; }
    public virtual Post? Post { get; set; }
}

Ваша первоначальная проблема-это предупреждение о том, что в C#8 было введено более четкое определение типов ссылок с нулевой возможностью. Для сущности приведенная выше реализация недопустима, если только эти отношения действительно не являются необязательными, что потребует, чтобы их поля FK (идентификатор пользователя и идентификатор поста) также были пустыми. Скорее всего, они не являются необязательными.

Основные варианты решения этой проблемы:

А) Выключите эту функцию. (Отключить нулевые ссылки в проекте)

Б) Попросите "прощения" за то, что они никогда не должны быть нулевыми, но не будут находиться в действительном состоянии при строительстве. (EF будет управлять ими)

public class PostFile {
    public Int32 UserId{ get; set; }
    public Int32 PostId { get; set; }

    public virtual User User { get; set; } = null!;
    public virtual Post Post { get; set; } = null!;
}

Изменение модели для пометки свойств навигации как ссылок, допускающих нуль, вероятно, вызовет всевозможные проблемы, как и при миграции, и начнет заменять ненулевые FK на нуль-способные. Чтобы отметить эти ссылки как недействительные и сделать EF счастливым:

public class PostFile {
    public Int32? UserId{ get; set; }
    public Int32? PostId { get; set; }

    public virtual User? User { get; set; }
    public virtual Post? Post { get; set; }
}

Что почти наверняка не то, что вы хотите в своем домене, или даже законно, если идентификатор пользователя и идентификатор postID являются частью ПК.

Лично я отмечаю это изменение в C# как "мину" MS, изначально включенную по умолчанию, например, оценку на стороне клиента в EF. :) Я предвижу множество вопросов StackOverflow, связанных с этим предупреждением или критическими изменениями, и множество клиентских кодовых баз, усеянных тегами прощения"!", поскольку более старые объекты/ссылки, не способные к нулю, передаются в код с проверкой ссылок на нуль.

2021-11-24 23:15:24
1

Вы должны пометить объекты навигации как обнуляемые. У вас не должна быть включена отложенная загрузка, и поэтому свойства навигации могут быть возвращены как null из запросов. Даже если они требуются в базе данных, вашему коду не нужно их загружать.

В выражениях ваших запросов вы можете быть уверены, что Entity Framework не будет выполнять их на стороне клиента, а проанализирует SQL-запрос на их основе.

Следовательно:

.Where(x => x.User!.Id == request.UserId)

Вы можете сообщить компилятору с помощью User! что вы знаете, что там это не будет равно нулю. Если вы не включите оценку на стороне клиента, но вы не должны этого делать, и если вы это сделаете, вам все равно понадобится проверка на ноль.

Что касается использования PostFile.User, как в:

var postFile = dbContext.PostFiles.FirstOrDefault(p => p....) ?? throw ...;
var user = postFile.User;

Там это может быть null если бы вы этого не сделали Include(p => p.User) и не включайте ленивую загрузку, так что user перед использованием потребуется проверка на ноль.

Если вы используете отложенную загрузку, вы можете отключить предупреждение:

#pragma warning disable CS8618 // EF initializes these properties through lazy loading
    public virtual User User { get; set; }
#pragma warning restore CS8618 
2021-11-24 22:37:30
0

Я думаю, тебе это нужно:

public class PostFile {
    public User User { get; set; }
    public Post Post { get; set; }
}

И позвони

var postFiles = context.postFiles.Where(x => x.User.Id == request.UserId).Include(x => x.Post);
2021-11-24 22:52:47

Нет. Если эти свойства не помечены как обнуляемые, компилятор выдает предупреждения о том, что они могут не быть инициализированы, что верно.
CodeCaster
0

Что о var postFiles = context.postFiles.Where(x => x.User != null && x.User.Id == request.UserId);?

2021-11-24 22:53:01

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................