25

I am working with Entity Framework Code first. I have a simple model:

public class Variable
{
    public string Name { get; set; }

    public int Id { get; set; }

    public IList<string> TextOptions
    {
        get;
        set;
    }
}

I ran into issues with the Property TextOptions being of type List<String>.

When I try to do this in Entity Framework, it does not map.

I found a solution on here (stackoverflow) that fixes my issue. I basically rework my class so that it takes the list and makes it a delimited string which gets persisted instead:

public class Variable : IVariable
{
    public string Name { get; set; }

    public int Id { get; set; }

    public virtual IList<string> TextOptions
    {
        get
        {

            return _TextOptions;

        }
        set
        {
            _TextOptions = value;
        }
    }

    private IList<string> _TextOptions;

    public string TextOptionsSerialized
    {
        get
        {
            return String.Join(";", _TextOptions);
        }
        set
        {
            _TextOptions = value.Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries).ToList();
        }
    }
}

This code works fine. The problem that I have with it is that I think that it violates Separation of Concern. I don't think my model class should be concerned with serializing a list of strings so that Entity framework can persist it.

I ran into a similar issue working in ASP.Net MVC. I had a post sent from the client that would be mapped to a model. There were some issues with the way the model was structured compared to the post. In MVC I could write a Custom Model Binder to handle the conversion in a very safe and reusable fashion.

Is there ANY way I can do this for Entity Framework that is as clean as Custom Model Binders are for MVC?

Mike Bynum
  • 763
  • 2
  • 10
  • 22

2 Answers2

26

No, EF doesn't have any type converters or custom type mappers as alternative to model binders from MVC. You must always use some hack to force persistence. Another way to do the same is mapping TextOptions as collection of related entities. It will make your separation of concerns better but it will complicate your model and working with Variable.

public class Variable
{
    public string Name { get; set; }

    public int Id { get; set; }

    public IList<TextOption> TextOptions
    {
        get;
        set;
    }
}

public class TextOption
{
    public int Id { get; set; }
    public string Text { get; set; }
}
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 2
    Thanks for your response. Sad to hear it though! This whole claim about code first seems to only be half a step in the right direction. I cant create models that are agnostic to EF unless they provide SOMETHING like model binders. – Mike Bynum Nov 30 '11 at 18:00
  • 5
    I just wanted to add that you can't be disappointed in EF about this. It is a limitation brought about by the inherent differences between a relational data model and an object oriented data model. Different concepts. – KellySandwiches May 11 '13 at 21:35
  • 4
    @KellySandwiches The mapping from `List` to a table with an `id` and a `value` is pretty straightforward and common enough that it could be done automatically by EF, right?. – Matthijs Wessels Sep 16 '14 at 08:22
  • 1
    The $1M dollar pragmatic question: which approach will yield better performance? Serialization or introducing an additional entity> – Mauricio Aviles Oct 20 '14 at 06:16
  • @MauricioAviles If I answer it, will you give me $1M ;)? – JabberwockyDecompiler Jun 12 '15 at 15:09
7

A 3rd option would be to do the serialization using JSON.NET.

I ran some performance tests for write scenarios using the 3 options listed on this thread (String split serialization, JSON.NET, and introducing an entity) and found that JSON.NET yields the best performance.

Preliminary write results of 200 equal entities (see source code here and run the test yourself):

  • Time to write entities using string serializer: 896 miliseconds
  • Time to write entities using json serializer: 516 miliseconds
  • Time to write entities using multiple entities: 706 miliseconds

Sample using JSON serializer:

public class VariableJson
{
    public string Name { get; set; }

    public int Id { get; set; }

    public virtual IList<string> TextOptions
    {
        get
        {

            return _TextOptions;

        }
        set
        {
            _TextOptions = value;
        }
    }

    private IList<string> _TextOptions;

    public string TextOptionsSerialized
    {
        get
        {
            return JsonConvert.SerializeObject(_TextOptions);
        }
        set
        {
            _TextOptions = JsonConvert.DeserializeObject<IList<string>>(value);                    
        }
    }
}
Mauricio Aviles
  • 1,074
  • 9
  • 24
  • 4
    I wonder whether the relative performance is different if you have only 2 or 3 strings in your list. What about 10,000? – Daniel Dyson Jul 16 '15 at 22:59