Entity Framework задает свойство навигации null

У меня есть первый проект базы данных сущности. вот извлечение модели:

public partial class LedProject
{
    public LedProject()
    {
        this.References = new HashSet<LedProjectReference>();
        this.Results = new HashSet<LedProjectResult>();
        this.History = new HashSet<LedProjectHistory>();
    }

    public string Identifier { get; set; }
    public string Name { get; set; }
    public Nullable<System.DateTime> CompletionDate { get; set; }
    public System.DateTime CreationDate { get; set; }
    public System.Guid ProjectId { get; set; }
    public string Comment { get; set; }

    public virtual User ContactUser { get; set; }
    public virtual User CreationUser { get; set; }
    public virtual Customer Customer { get; set; }
    public virtual LedProjectAccounting Accounting { get; set; }
    public virtual LedProjectState State { get; set; }
    public virtual ICollection<LedProjectReference> References { get; set; }
    public virtual ICollection<LedProjectResult> Results { get; set; }
    public virtual User ResponsibleUser { get; set; }
    public virtual ICollection<LedProjectHistory> History { get; set; }
}
public partial class User
{
    public System.Guid UserId { get; set; }
    public string LoginName { get; set; }
    public System.DateTime CreationDate { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
}

У меня проблема с настройкой элемента навигации ResponsibleUser для класса LedProject. Когда я устанавливаю ResponsibleUser другому пользователю и впоследствии сохраняю изменения в DBC-тексте, изменения сохраняются в базе данных.

Но, когда я хочу удалить текущий ResponsibleUser из LedProject, установив свойство навигации в значение null. Изменения не сохраняются в базе данных.

LedProject project = db.LedProject.Find(projectId);
project.Name = string.IsNullOrEmpty(name) ? null : name;
...
project.ResponsibleUser = responsibleUser == null ? null : db.User.Find(responsibleUser.UserId);
...
db.SaveChanges();

Есть ли какой-либо трюк для удаления свойств навигации?

Ответы

Ответ 1

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

LedProject project = db.LedProject
    .Include("ResponsibleUser")
    .Where(p => p.ProjectId == projectId)
    .FirstOrDefault();

Загружает ResponsibleUser, когда загружается Проект. Это, наконец, решило мою проблему!

Ответ 2

Как boindiil, проблема связана с ленивой загрузкой. Однако вам нужно только загрузить свойство, когда вы хотите его обнулить, чтобы механизм Entity Framework знал, что он изменился. Код может выглядеть так:

responsibleUser = responsibleUser == null ? null : db.User.Find(responsibleUser.UserId);
if (responsibleUser == null)
{
    // load the value to assure setting it to null will cause a change
    var dummy = project.ResponsibleUser; 
}

project.ResponsibleUser = responsibleUser;
...
db.SaveChanges();

Я продолжаю думать, что должен быть способ использовать db.ChangeTracker, чтобы принудительно сохранить без нагрузки, но я еще не нашел его (и несколько вещей, которые я пробовал, выглядели действительно взломанными).

Ответ 4

Придумал лучший способ сделать это без необходимости загружать свойство навигации, чтобы вы все еще могли использовать EF Find() и не должны делать взлома.

Используйте примитивный идентификатор рядом с навигационным свойством, где тип - это любой тип идентификатора свойств навигации (обычно строка для пользователей), например:

public partial class LedProject
{
    public string ResponsibleUserId { get; set; }
    public virtual User ResponsibleUser { get; set; }
}

Обновите строку с помощью свойства навигации везде, где вы создаете запись, а затем, когда вы хотите удалить отношения, просто выполните ledProject.ResponsibleUserId = null.

Если вы назовете id что-то другое, кроме свойств навигации name + id в конце, вам нужно будет использовать аннотации или свободно отображаемые api для отображения, которые я думаю.

Дополнительная информация здесь: В каких сценариях мне нужны внешние ключи и свойства навигации в инфраструктуре сущности

Ответ 5

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

Просто определите свойство на вашей модели следующим образом:

    public int? AccountId { get; set; }

    //workaround for entity framework lazy loading problem

    Account account;

    public virtual Account Account
    {
        get
        {
            return account;
        }
        set
        {
            account = value;


            if (value == null)
            {
                AccountId = null;
            }

        }
    }

Теперь вам не нужно с нетерпением загружать свойство навигации и устанавливать его значение null. Что еще более важно, если вы перенесите хак непосредственно внутри своей сущности, вам не придется забывать делать явные проверки где-либо еще в кодовой базе.