在使用EF Core更新实体的时候,其中一对一关系的导航没有被跟踪到。
实体如下:
public class Post
{
...
public int Id { get; set;}
public Body Body {get; set;}
...
}
public class Body
{
...
public int PostId {get; set;}
public Post Post {get; set;}
public string Content {get; set;}
...
}
映射关系:
modelBuilder.Entity<Post>().HasOne("Body").WithOne("Post").HasForeignKey("PostId");
modelBuilder.Entity<Body>().HasOne("Post").WithOne("Body").HasForeignKey("Id");
更新实体:
var aPost = new Post(100, new Body(100, "updated-body");
var aUpdatedPost = _dbContext.Update(aPost);
_dbContext.SaveChanges();
结果发现Post.Body.Conent
根本没有更新,而且在Debug
模式中,观察到了Post.Body
属性根本没有被跟踪。
于是,手动设置其State=IsModified
:
aUpdatedPost.Navigation("Body").IsModified = true;
结果报错了:
System.InvalidOperationException : The property 'PostId' on entity type 'Body' is part of a key and so cannot be modified or marked as modified.
请问这是什么原因?DbContext.Update
方法不是说好了会递归遍历所有的导航属性并设置为Modified
或者Added
状态吗?
当前场景中不仅没有设置为Modified
而且还不能手动设置,连异常信息也让人摸不着头脑。
这个一对一关系有点特殊,它是通过共享主键的方式,即Post
的主键同步到Body
的主键,因此,这里的外键关联用的主键。
当前的解决办法:分别修改
var aPost = new Post(100, new Body(100, "updated-body");
_dbContext.Update(aPost.Body);
var aUpdatedPost = _dbContext.Update(aPost);
_dbContext.SaveChanges();
先修改导航属性,再修改实体。
数据库里能看到外键吗.
逻辑上的外键,数据库中并没有指定。
@蝌蝌: 如果你配置正确.他会在数据库里创建一个外键的.
var bind = modelBuilder.Entity<FieldGroups>();
bind.HasRequired(a=>a.Users).WithOptional(a=>a.Count).Map()
你试试这种写法.
@吴瑞祥:
不是自动生成的数据库,而且不检测数据库和Code中定义的模型是否一致。
另外,这是EF Core。貌似没有HasRequired
这个方法。
@蝌蝌: 这个就是从efcore的项目里复制过来的.
要先确定你的绑定代码是对的.