EF Core

时间:2017-10-22 09:18:19

标签: c# entity-framework entity-framework-core ef-core-2.0

我试图在EF Core中实现一些在EF 6中非常适合我的东西。

我将List<T>属性的内容序列化为DB中的Json字符串。 <T>可以是几乎任何东西,因为Json.Net负责序列化我们抛出的任何东西。我的集合公开了一个Json字符串属性,负责序列化/反序列化。

这种方法对于结构化嵌套数据来说非常方便有效,而关系模型会带来不必要的开销和复杂性。

在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不支持映射泛型类型,因此我们为每种类型的List提供了一个具体的实现:

public class PhoneNumberCollection : SelfSerializingCollection<PhoneNumber> { }

然后像这样使用它:

public class Contact {
    public PhoneNumberCollection PhoneNumbers { get; set; }
}

就是这样。现在,我试图在EF Core 2.0中实现相同的目标。

这是我到目前为止所拥有的。 SelfSerializingCollection<T>类没有变化。

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集合的任何更改都 被持久保存回数据库。我正在使用_context.Entry(contactModelFromRequestBody).State = EntityState.Modified;更新典型的PUT方法 - 与之前相同。但由于某种原因,EF Core不会将Json字符串属性保留回Modified实体的数据库。

有什么想法吗?

2 个答案:

答案 0 :(得分:8)

EF Core将拥有的类型视为没有自己身份的实体类型,因此指向拥有类型的属性将被视为导航属性。将父实体状态设置为Update不会级联到导航属性。

然而,DbContextDbSet的{​​{1}}方法会级联,因此不是

_context.Entry(contactModelFromRequestBody).State = EntityState.Modified;

你应该使用

_context.Update(contactModelFromRequestBody);

答案 1 :(得分:1)

似乎有必要为我拥有的类型手动设置修改后的实体状态:

_context.Entry(contact).Reference(p => p.PhoneNumbers)
    .TargetEntry.State = EntityState.Modified;

这就是诀窍,尽管我仍然希望找到一个更通用的解决方案,并不要求我在每次更新时都标记所有拥有的属性。