Entity framework 无法获取实体框架中导航属性的更新关系
我目前正在使用EF4.3和代码优先。创建我的对象是可行的(通过我的视图-仅使用自动生成的创建),但当我尝试编辑对象时,它不会保存任何与我的导航属性相关的更改。我一直是,但我不明白如何告诉我的背景关系已经改变 下面是我实现的一些示例代码Entity framework 无法获取实体框架中导航属性的更新关系,entity-framework,code-first,Entity Framework,Code First,我目前正在使用EF4.3和代码优先。创建我的对象是可行的(通过我的视图-仅使用自动生成的创建),但当我尝试编辑对象时,它不会保存任何与我的导航属性相关的更改。我一直是,但我不明白如何告诉我的背景关系已经改变 下面是我实现的一些示例代码 @* Snippet from my view where I link into my ViewModel. *@ <div class="row"> <div class="editor-label"> @Htm
@* Snippet from my view where I link into my ViewModel. *@
<div class="row">
<div class="editor-label">
@Html.LabelFor(model => model.ManagerID)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.ManagerID, ViewBag.Manager as SelectList, String.Empty)
@Html.ValidationMessageFor(model => model.ManagerID)
</div>
</div>
在我的项目对象中:
public class Project
{
public int ProjectID { get; set; }
[Required]
public string Name { get; set; }
// Navigation Properties
public virtual User Manager { get; set; }
}
以下是存储库(我的上下文所在的位置)中相应的方法:
需要明确的是,这确实可以更新我的属性,但不会更新我的导航属性(在本例中是Manager)。感谢您的帮助。我不太清楚您所说的导航属性到底是什么意思?你是说像外键关系?如果是,请尝试以下数据注释:
public class Project
{
public int ProjectID { get; set; }
[Required]
public string Name { get; set; }
[ForeignKey("YourNavigationProperty")]
public virtual UserManager { get; set; }
}
更新EF上下文,看看会发生什么
更新
查看是否有效?将状态设置为“已修改”仅将标量属性标记为已修改,而不是导航属性。您有几个选择:
- 黑客(你不会喜欢的)
- 从数据库中重新加载项目,包括(立即加载)当前管理器。然后设置属性。更改跟踪将再次检测管理器的更改并写入更新
- 在模型中为
导航属性公开外键属性:管理器
现在,public class Project { public int ProjectID { get; set; } [Required] public string Name { get; set; } public int ManagerID { get; set; } public virtual User Manager { get; set; } }
是一个标量属性,将状态设置为ManagerID
将包括此属性。此外,您不需要从数据库加载Manager用户,只需分配从视图中获得的ID即可:Modified
Project project = new Project(); project.ProjectID = projectViewModel.ProjectID; project.Name = projectViewModel.Name; project.ManagerID = projectViewModel.ManagerID; repository.InsertOrUpdateProject(project); repository.Save();
- 这里有几个选项,我将列出其中3个:
选项1:使用GraphDiff
*这需要将上下文的
配置.AutoDetectChangesEnabled
设置为true
只需使用NuGet安装GraphDiff
Install-Package RefactorThis.GraphDiff
然后
有关GraphDiff的更多详细信息,请参见
选项2:查找和编辑
使用EF搜索实体以将其跟踪到上下文。然后编辑属性
*这需要将上下文的配置.AutoDetectChangesEnabled
设置为true
选项3:使用标量属性
就性能而言,这是最好的方法,但它会让您的类陷入数据库问题。因为需要创建标量(基元类型)属性来映射Id
*这样就不需要将配置.AutoDetectChangesEnabled
设置为true。而且,您也不需要查询数据库来检索实体(前两个选项会这样做-是的,GraphDiff会在幕后执行!)
所以我没有明确定义我的FK名称。我希望能够将我的管理器值设置为一个新的管理器(似乎可以工作),但在调用SaveChanges()时,更改实际上不会持久化到数据库中。我不知道该怎么做,太好了。非常感谢。我最初做了外键路由,但有一些问题。事实证明,这是可行的,但我必须使用导航属性定义[ForeignKey(“Name”)]属性,以便所有内容都能正确映射。接受你的回答。谢谢@user1240560:对于我答案中的名称,它实际上应该在没有ForeignKey属性的情况下工作(根据名称约定进行FK检测)。但是如果你的名字差别太大,不符合惯例规则,那么是的,你需要注释。@Slauma我爱你,其他方法应该适用于代码优先模型,但首先适用于数据库,唯一对我有效的方法是你的黑客攻击,我已经干扰了好几天,现在我不得不说我非常爱你来自未来的感谢真的很有帮助,我相信如果
Configuration.AutoDetectChangesEnabled=true代码>不起作用,然后检查其他选项
//...
else
{
var manager = project.Manager;
project.Manager = null;
context.Entry(project).State = EntityState.Modified;
// the line before did attach the object to the context
// with project.Manager == null
project.Manager = manager;
// this "fakes" a change of the relationship, EF will detect this
// and update the relatonship
}
public class Project
{
public int ProjectID { get; set; }
[Required]
public string Name { get; set; }
public int ManagerID { get; set; }
public virtual User Manager { get; set; }
}
Project project = new Project();
project.ProjectID = projectViewModel.ProjectID;
project.Name = projectViewModel.Name;
project.ManagerID = projectViewModel.ManagerID;
repository.InsertOrUpdateProject(project);
repository.Save();
Install-Package RefactorThis.GraphDiff
using (var context = new Context())
{
var customer = new Customer()
{
Id = 12503,
Name = "Jhon Doe",
City = new City() { Id = 8, Name = "abc" }
};
context.UpdateGraph(customer, map => map.AssociatedEntity(p => p.City));
context.Configuration.AutoDetectChangesEnabled = true;
context.SaveChanges();
}
var customer = new Customer()
{
Id = 12503,
Name = "Jhon Doe",
City = new City() { Id = 8, Name = "abc" }
};
using (var context = new Contexto())
{
var customerFromDatabase = context.Customers
.Include(x => x.City)
.FirstOrDefault(x => x.Id == customer.Id);
var cityFromDataBase = context.Cities.FirstOrDefault(x => x.Id == customer.City.Id);
customerFromDatabase.Name = customer.Name;
customerFromDatabase.City = cityFromDataBase;
context.Configuration.AutoDetectChangesEnabled = true;
context.SaveChanges();
}
var customer = new Customer()
{
Id = 12503,
Name = "Jhon Doe",
City_Id = 8,
City = null
};
using (var contexto = new Contexto())
{
contexto.Entry(customer).State = EntityState.Modified;
contexto.SaveChanges();
}