拥有的类型 属性 不会为 EF Core 中修改后的实体保留
Owned type property not persisting for a modified entity in EF Core
我正在尝试在 EF Core 中实现一些在 EF 6 中对我非常有用的东西。
我正在将 List<T>
属性 的内容序列化为数据库中的 Json 字符串。 <T>
几乎可以是任何东西,因为 Json.Net 负责序列化我们扔给它的任何东西。我的 collection 公开了一个 Json
字符串 属性 并处理 serializing/deserializing 本身。
对于关系模型会带来不必要的开销和复杂性的结构化嵌套数据,此方法既方便又高效。
在 EF 6 中我会做这样的事情:
[ComplexType]
public class SelfSerializingCollection<T> : Collection<T>
{
public void AddRange(IEnumerable<T> collection)
{
foreach (var item in collection)
{
Add(item);
}
}
protected string Json
{
get { return JsonConvert.SerializeObject(this); }
private set
{
Clear();
if (value == null)
{
return;
}
AddRange(JsonConvert.DeserializeObject<T[]>(value));
}
}
}
EF 6 不支持映射泛型类型,因此我们将为我们可能需要的每种类型的列表提供具体实现:
public class PhoneNumberCollection : SelfSerializingCollection<PhoneNumber> { }
然后像这样使用它:
public class Contact {
public PhoneNumberCollection PhoneNumbers { get; set; }
}
就是这样。现在,我正在尝试在 EF Core 2.0 中实现相同的目标。
这是我目前所拥有的。 SelfSerializingCollection<T>
class 不变。
public class Contact {
// EF Core supports generic types so we don't need a concrete implementation
// for each collection type.
public SelfSerializingCollection<PhoneNumber> PhoneNumbers { get; set; }
}
public class MyDbContext : DbContext
{
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// EF Core does not support the [ComplexType] attribute
// but we now have .OwnsOne() in EF Core 2
modelBuilder.Entity<Contact>().OwnsOne(p => p.PhoneNumbers);
}
}
到目前为止一切顺利。 EF Core 映射数据库中的 PhoneNumbers_Json
列。阅读和创建新条目效果很好。
但是,与 EF 6 不同的是,对现有实体的 PhoneNumbers
collection 的任何更改都 不会 持久保存回数据库。我正在使用 _context.Entry(contactModelFromRequestBody).State = EntityState.Modified;
使用典型的 PUT 方法进行更新 - 与以前相同。但出于某种原因,EF Core 没有将我的 Json
字符串 属性 保存回数据库以获取 Modified
实体。
有什么想法吗?
似乎有必要为我拥有的类型手动设置修改后的实体状态:
_context.Entry(contact).Reference(p => p.PhoneNumbers)
.TargetEntry.State = EntityState.Modified;
虽然我仍然希望找到一个更通用的解决方案,它不需要我在每次更新时都像这样标记所有拥有的属性,但它确实有效。
EF Core 将自有类型视为实体类型 w/o 自有身份,因此指向自有类型的属性被视为导航属性。并且将父实体状态设置为 Modified
不会级联到导航属性。
但是 DbContext
或 DbSet
的 Update
方法确实级联,所以
_context.Entry(contactModelFromRequestBody).State = EntityState.Modified;
你应该使用
_context.Update(contactModelFromRequestBody);
我正在尝试在 EF Core 中实现一些在 EF 6 中对我非常有用的东西。
我正在将 List<T>
属性 的内容序列化为数据库中的 Json 字符串。 <T>
几乎可以是任何东西,因为 Json.Net 负责序列化我们扔给它的任何东西。我的 collection 公开了一个 Json
字符串 属性 并处理 serializing/deserializing 本身。
对于关系模型会带来不必要的开销和复杂性的结构化嵌套数据,此方法既方便又高效。
在 EF 6 中我会做这样的事情:
[ComplexType]
public class SelfSerializingCollection<T> : Collection<T>
{
public void AddRange(IEnumerable<T> collection)
{
foreach (var item in collection)
{
Add(item);
}
}
protected string Json
{
get { return JsonConvert.SerializeObject(this); }
private set
{
Clear();
if (value == null)
{
return;
}
AddRange(JsonConvert.DeserializeObject<T[]>(value));
}
}
}
EF 6 不支持映射泛型类型,因此我们将为我们可能需要的每种类型的列表提供具体实现:
public class PhoneNumberCollection : SelfSerializingCollection<PhoneNumber> { }
然后像这样使用它:
public class Contact {
public PhoneNumberCollection PhoneNumbers { get; set; }
}
就是这样。现在,我正在尝试在 EF Core 2.0 中实现相同的目标。
这是我目前所拥有的。 SelfSerializingCollection<T>
class 不变。
public class Contact {
// EF Core supports generic types so we don't need a concrete implementation
// for each collection type.
public SelfSerializingCollection<PhoneNumber> PhoneNumbers { get; set; }
}
public class MyDbContext : DbContext
{
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// EF Core does not support the [ComplexType] attribute
// but we now have .OwnsOne() in EF Core 2
modelBuilder.Entity<Contact>().OwnsOne(p => p.PhoneNumbers);
}
}
到目前为止一切顺利。 EF Core 映射数据库中的 PhoneNumbers_Json
列。阅读和创建新条目效果很好。
但是,与 EF 6 不同的是,对现有实体的 PhoneNumbers
collection 的任何更改都 不会 持久保存回数据库。我正在使用 _context.Entry(contactModelFromRequestBody).State = EntityState.Modified;
使用典型的 PUT 方法进行更新 - 与以前相同。但出于某种原因,EF Core 没有将我的 Json
字符串 属性 保存回数据库以获取 Modified
实体。
有什么想法吗?
似乎有必要为我拥有的类型手动设置修改后的实体状态:
_context.Entry(contact).Reference(p => p.PhoneNumbers)
.TargetEntry.State = EntityState.Modified;
虽然我仍然希望找到一个更通用的解决方案,它不需要我在每次更新时都像这样标记所有拥有的属性,但它确实有效。
EF Core 将自有类型视为实体类型 w/o 自有身份,因此指向自有类型的属性被视为导航属性。并且将父实体状态设置为 Modified
不会级联到导航属性。
但是 DbContext
或 DbSet
的 Update
方法确实级联,所以
_context.Entry(contactModelFromRequestBody).State = EntityState.Modified;
你应该使用
_context.Update(contactModelFromRequestBody);