7

Example: Let's say I have these three classes. Foo is a proper Entity Framework entity with a DbSet whereas I want my EF DbContext to be unaware of Bar and Baz because I have flagged Foo's Bar property with my made up SerializedColumn attribute. By applying that attribute, I want EF to serialize the instance of Bar with its Bazes into a single string field, and transparently deserialize Bar to a Bar object when a Foo is materialized by EF.

public class Foo
{
    public Guid Id { get; set; }
    [SerializedColumn]
    public Bar Bar { get; set; }
    // ..
}

public class Bar
{
    public string Name { get; set; }
    public Baz[] Baz { get; set; }
    // ..
}

public class Baz
{
    public string Name { get; set; }
    // ..
}

So Foo's table columns would look like:

[Id] [uniqueidentifier] NOT NULL
[Bar] [nvarchar](max) NULL

And when I query a Foo I get back one with the Bar property already deserialized. When I insert or update a Foo the Bar property gets serialized by EF without me having to think about it. The only thing I have to do is add the [SerializeColumn] attribute to properties.

Goals:

  • I'm not necessarily looking for a full blown solution (although I would accept it) but for guidance on where to jump into EF's pipeline, and how to do that. I.E. what EF classes, configurations, conventions, etc. do I need to take into account?
  • I want Migrations to be generated as one would expect. Which is to say, I wouldn't want my Bar property to turn into a "Bar_Id" field that points to a "Bar" table. Instead I want a nvarchar(max) "Bar" field that will contain the serialized version of a Bar object. If this simply isn't possible, please say so in your answer.

Notes:

  • The idea for this came after watching the Building Applications with Entity Framework 6 video by Rowan Miller.
  • ComplexType does not serve my needs. I need deep serialization and do not need to be able to filter or sort on any properties of what has been serialized.
  • I plan on serializing with Newtonsoft's JSON library, but how serialization happens doesn't really matter.
Jeremy Cook
  • 20,840
  • 9
  • 71
  • 77
  • Something like this? http://stackoverflow.com/questions/14779740/can-i-embed-an-object-in-an-ef-entity-serialize-on-save-deserialize-on-access – MutantNinjaCodeMonkey Nov 24 '15 at 23:24
  • @MutantNinjaCodeMonkey I've done that in the past and it works, but am looking to make persistence totally transparent. That is only one property `Bar` with my made up `SerializeColumnAttribute`, and no `BarSerialized` property. – Jeremy Cook Nov 24 '15 at 23:30
  • 2
    Pretty sure this is not possible in EF6. What you really need is a customer type converter. That feature is [planned](https://github.com/aspnet/EntityFramework/issues/242) for EF7 but not yet implemented. – DavidG Dec 02 '15 at 01:36

2 Answers2

10

The only solution is this,

public class Foo
{
    public Guid Id { get; set; }

    // Not Mapped attribute will make EF
    // ignore this property completely
    [NotMapped]
    public Bar BarObject { 
      get;
      set;
    }

    public string Bar{
       get{
          return JsonConvert.Serialize(BarObject);
       }
       set{
          BarObject = JsonConvert.Deserialize<BarObject>(value);
       }
    }
}

Updated as per suggestion by @zds

Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • Thank you Akash but I gave the bounty to @bubi since he answered first with essentially the same answer as you, albeit a little less detailed. If I could, I would have split the bounty between both answers. – Jeremy Cook Dec 08 '15 at 21:23
  • 1
    Could it be better to move serialization logic to 'public string Bar' property. Not to serialize and deserialize all the time, when changing something. Or am I missing something? – zds Aug 03 '16 at 15:52
1

No way to do it without modifing EF. With EF 6 I think that several people did it with a text backing field and some limitations (Bar and Bar children does not access to EF persisted property or you need other work after deserialization).

bubi
  • 6,414
  • 3
  • 28
  • 45
  • I'd be just fine with the limitations that come with a text backing field in the database (no filtering, in-database projections, etc.). Or by text backing field are you referring to using two properties, one marked [NotMapped] that is the in-memory, decrypted version of the encrypted property that EF will persist? – Jeremy Cook Dec 03 '15 at 18:25
  • For backing field I mean two properties, one marked [NotMapped] that is the in-memory, decrypted version of the encrypted property that EF will persist. – bubi Dec 03 '15 at 19:03
  • Well, nothing wrong with backing properties if that's what it comes to. Thanks @bubi I'm going to let this bounty linger for a bit longer to see if anyone else can add some helpful information. – Jeremy Cook Dec 03 '15 at 20:05