Raston
Raston

Reputation: 91

Store any object as as string, but expose as typed object or Map a non-string property of any type to a string column

I need to store different parameters in the database using EntityFramework. The value needs to be stored in string type, but there is additional column which specifies if it's string, int, double etc.

But then, when I retrieve values from the database, I need to map it to valid type. Simplified classes look like that:

public class Parameter
{
    public long Id {get; set;}
    public string Type {get; set;}
}

public class ParameterValues
{
    public long Id {get; set;}
    public virtual Parameter {get;set;}
    public string Value {get;set;}
}

public class Document
{
    public long Id {get; set;}
    public virtual ICollection<ParameterValues> ParameterValues {get;set;}
}

So, I guess I need to write a method which will convert retrivied Value from the database, but I have no idea how to do that.

I've tried writing additional classes like:

public class IntValue : ParameterValue
{
    public new int Value {get;set;}
}

Then my method would iterate over collection:

private void Convert()
{
    foreach (ParameterValue param in ParameterValues)
    {
        if (param.Parameter.Type == "Int")
        {
            IntParameter intParameter = param;
        }
    }
}

But of course it doesnt work this way. Anyone have idea how to map string values to ParameterValue class with correct value type?

Upvotes: 0

Views: 75

Answers (2)

JotaBe
JotaBe

Reputation: 39004

When I need to do somethign like this, I use a [NotMapped] property that allows me to retrieve and store the values like this:

[NotMapped]
public object TypedValue
{
    get 
    { 
       switch(Type)
       {
          case "int":
             return int.Parse(Value); // parse to whatever needed, with a switch
          // ...
       }
    }
    set
    {
      switch(value.GetType)
      {
          case typeof(int):
             Value = // format to allow later parsing
             break;
          // ...
      }
    }
}

There are details ommited (for example, null treatment).

However, the most reasonable way to do it is to use a serializer (JSON, Binary, XML or whatever) to serialize and deserialize the value, so that you avoid all the switches (if you do it rigth, the serialized value has type information to allow direct deserialization to the correct type). I'd expose a [NotMapped] object Value property and include a SerializedValue mapped to a db column, and instead of formatting and parsing, I'd use "serialize/deserialize", in a way similar to the sample code.

Upvotes: 1

mclaassen
mclaassen

Reputation: 5128

How about something like:

public class Parameter
{
    public long Id {get; set;}
    public string Type {get; set;}
}

public class ParameterValues
{
    public long Id {get; set;}
    public Parameter Parameter {get; set;}
    public string Value {get;set;}

    public ParameterValues(long id, Parameter param, string val)
    {
        Id = id;
        Parameter = param;
        Value = val;
    }
}

public class IntValue : ParameterValues
{
    public IntValue(ParameterValues value)
        : base(value.Id, value.Parameter, value.Value)
    {
    }

    public int GetValue()
    {
        return Int32.Parse(Value);
    }
}

and then Convert could be something like:

public List<ParameterValues> Convert(List<ParameterValues> values)
{
    var newValues = new List<ParameterValues>();

    foreach (var val in values)
    {
        if (val.Parameter.Type == "Int")
        {
            newValues.Add(new IntValue(val));
        }
    }

    return newValues;
}

Upvotes: 0

Related Questions