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, чтобы принудительно сохранить без нагрузки, но я еще не нашел его (и несколько вещей, которые я пробовал, выглядели действительно взломанными).
Ответ 3
Начиная с Entity Framework 5.0:
db.Entry(project).Reference(p => p.ResponsibleUser).CurrentValue = null;
https://msdn.microsoft.com/en-us/data/jj713564.aspx
Ответ 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. Что еще более важно, если вы перенесите хак непосредственно внутри своей сущности, вам не придется забывать делать явные проверки где-либо еще в кодовой базе.