我的客户端有一个有效负载是一个对象,它的属性是基元,其他对象的属性也是基元。
例如:
public class MainObj
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id {get;set;}
public string foo {get;set;}
public OtherObj bar {get;set;}
}
public class OtherObj
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id {get;set;}
public int test {get;set;}
}
验证请求后,我会收到用户尝试更新的对象:
var obj = _context.MainObjs.Select(x => new MainObj
{
id = x.id,
foo = x.foo,
bar = x.bar
}).SingleOrDefaultAsync(x => x.id == request.id);
我正在做.Select
,因为如果我不这样做,那么bar
永远不会被填充。
然后我用来自客户端的内容更新属性:
obj.foo = request.foo;
obj.bar = request.bar;
然后我尝试保存更改:
_context.SaveChangesAsync();
但是,当我这样做时,数据库中没有任何内容。我究竟做错了什么?我过去只使用过EF6,所以如果EFCore对使用外键关系更新对象感到奇怪,我就不知道了。而且要清楚,我的实际对象有更多的属性,但我不相信这是问题。
编辑:我尝试使用.Include
语法代替.Select
语法,如下所示:
var obj = _context.MainObjs.Include(x =>x.bar).SingleOrDefaultAsync(x => x.id == request.id);
然后我收到The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked.
EDIT2:用_context.Update(request)
替换所有其他代码正在运行。我很好奇为什么另一种方式不是。
答案 0 :(得分:2)
陈述......
_context.MainObjs.Select(x => new MainObj { ... })
...不会将任何内容附加到上下文中。它只是创建一个新的MainObj
对象,但EF并不知道它。在EF6中,不允许在EF LINQ查询中创建实体类型,以防止这种混淆。
因此,使用_context.MainObjs.Include(x =>x.bar)
,您会将MainObj
及其bar
附加到上下文中,并会跟踪其更改。
最后,语句_context.Update(request)
将request
附加到上下文并将其标记为Modified
,包括其bar
属性的外键。