【问题标题】:Can I Embed an object in an EF entity (serialize on save, deserialize on access)?我可以在 EF 实体中嵌入对象(保存时序列化,访问时反序列化)吗?
【发布时间】:2013-01-24 15:24:42
【问题描述】:

我有一个班级,我想保留元数据——有几个交互场景,所以元允许我为不同的交互类型保留不同的元数据。

class Feed()
{
    Guid FeedId { get; set; }
    ObjectMetaDictionary Meta { get; set; }
}

我希望 EF 序列化此 ObjectMetaDictionary 并将其作为字符串/VarChar 存储在数据库中。当我检索记录时,我希望将其反序列化为 ObjectMetaDictionary。

EF 支持这个吗?我该怎么做?

我首先使用实体​​框架代码。

已解决:我在下面提供了一个答案,解决了我的问题。只要允许,我就会接受这个答案。

【问题讨论】:

  • 更新:我在写完这个问题后不久就开始使用 MongoDB。对于 Mongo,这个问题甚至无关紧要,因为它很容易做到。在使用 SQL 时我喜欢 EF,但我宁愿在一周中的任何一天都使用 Mongo——根据 14 年的经验,我会说 mongo 在任何一天对 Web/应用程序都表现得更好。

标签: entity-framework ef-code-first


【解决方案1】:

HasConversion 功能救了我的命。解锁所有 json 格式!尽情享受吧!

public partial class Feed
{
    public int Id { get; set; }

    //this column will be mapped to a "nvarchar(max)" column. perfect!
    public Dictionary<string, string> Meta { get; set; }
}

public class FeedsDbContext : DbContext
{

    public FeedsDbContext(DbContextOptions<FeedsDbContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Feed> Feed { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Feed>(entity =>
        {
            entity.Property(p => p.Meta).HasConversion(
                x => JsonConvert.SerializeObject(x) //convert TO a json string
                , x => JsonConvert.DeserializeObject<Dictionary<string, string>>(x) //convert FROM a json string
            );
        });
    }

}

【讨论】:

    【解决方案2】:

    显然这实际上很容易。多亏了以前的 SO answer 的一些帮助,我才能让它工作。

    OnModelCreating 中的流畅配置允许我们告诉 EF 使用什么作为值属性来序列化到数据库并再次退出。

    这是我的解决方案:

    public class Feed
    {
        public virtual Guid FeedId { get; set; }
    
        public virtual FeedMetaData Meta { get; set; }
    
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
    
    }
    
    public class FeedMetaData
    {
        public Dictionary<string, string> Data { get; set; }
    
        public string Serialized
        {
            get { return JsonConvert.SerializeObject(Data); }
            set
            {
                if(string.IsNullOrEmpty(value)) return;
    
                var metaData = JsonConvert.DeserializeObject<Dictionary<string, string>>(value);
    
                Data = metaData ?? new Dictionary<string, string>();
            }
        }
    
        // addl code removed...
    }
    
    public class FeedsDbContext : DbContext
    {
        public DbSet<Feed> Feeds { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.ComplexType<FeedMetaData>()
                        .Property(p => p.Serialized)
                        .HasColumnName("Meta");
            modelBuilder.ComplexType<FeedMetaData>().Ignore(p => p.Data);
    
            base.OnModelCreating(modelBuilder);
        }
    }
    

    【讨论】:

    • 这是一项非常巧妙的工作,也是我在其他地方没有讨论过的一种技术,而且我自己也不会轻易解决。谢谢分享!
    • 不要忘记 EF(至少 EF6)将“_Serialized”或任何您调用的属性附加到您保存的字段中。在数据库优先方法的情况下,此信息可能有用
    • 或者你可以把[NotMapped]放在Data属性上。
    • 这将记录标记为脏,导致数据库查询。任何想法如何防止这种情况?
    • 我希望在重新发明轮子之前看到这个答案。我的略有不同采取stackoverflow.com/a/37207034/492
    【解决方案3】:

    让您的 Entity Framework 对象简单,并为数据库中的列提供一个 String 属性。

    class Feed()
    {
        Guid FeedId { get; set; }
        String Meta { get; set; }
    }
    

    创建这样保存和加载属性的方法:(自从我使用 EF 以来已经有一段时间了,所以我不确定您是否可以使用这些 getter/setter 创建瞬态属性,或者您是否需要其他东西)

    //Reading from string column Meta
    (ObjectMetaDictionary) XamlServices.Load(new StringReader(someFeed.Meta));
    
    //Saving to string column Meta
    someFeed.Meta = XamlServices.Save(value);
    

    不过,这会给您的项目带来另一个整体问题。更改您的 ObjectMetaDictionary 可能会导致它无法正确地从数据库中反序列化。您的 ObjectMetaDictionary 本质上成为您的数据库架构的一部分,您需要相应地处理版本控制或更改。

    【讨论】:

    • 是的,这基本上就是我现在拥有的方式,但是这种设计很弱,因为这意味着我总是必须有一个超类来处理序列化/反序列化。我希望能够使用 Feed.Meta 作为 ObjectMetaDictionary。
    • 你在做什么 EF 映射,代码优先,edmx 优先,...?
    • 代码首先,我更新了问题以表明这一点,以防有人错过我设置的标签。
    猜你喜欢
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多