Can I Embed an object in an EF entity (serialize on save, deserialize on access)?

后端 未结 3 1089
广开言路
广开言路 2020-12-08 03:08

I have a class that I want to keep meta data for -- there a several interaction scenarios so meta allows me to keep different meta for different interaction types.



        
相关标签:
3条回答
  • 2020-12-08 03:25

    Apparently this is actually quite easy. I was able to get it working thanks to some help from this previous SO answer.

    Fluent configuration in OnModelCreating allows us to tell EF what to use as the value property for serializing to the DB and back out again.

    Here's my solution:

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-08 03:26

    The feature HasConversion saved my life. Unlock all json formats! Enjoy it!

    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
                );
            });
        }
    
    }
    
    0 讨论(0)
  • 2020-12-08 03:38

    Have your Entity Framework object be simple and have a String property for the column in the database.

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

    Create methods that save and load the property as such: (it's been a while since I've used EF, so i'm not sure if you can create a transient property with these getter/setters or if you need something else)

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

    This brings another whole issue to your project though. Changing your ObjectMetaDictionary might cause it to not deserialize from the database correctly. Your ObjectMetaDictionary becomes essentially part of your database schema and you will need to handle versioning or changes accordingly.

    0 讨论(0)
提交回复
热议问题