Search code examples
c#wpfentity-frameworkdependency-properties

how to Store/Map Complex data type using EF?


CategoryModel has a property & dependency-property Color of type Object Brush (Complex data type) that can't be Stored using EF directly so I use Serialization and store it as string.

using System.ComponentModel.DataAnnotations.Schema;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
public class CategoryModel : UserControl{
...
    [NotMapped] // Not mapped to the database
    public Brush Color
    {
        get { return (Brush)GetValue(ColorProperty); }
        set { SetValue(ColorProperty, value); }
    }

    public static readonly DependencyProperty ColorProperty =
    DependencyProperty.Register("Color", typeof(Brush), typeof(CategoryModel), new PropertyMetadata(Brushes.Black));
...
}

so the solution is to use get & set to & from another property let's call it serializedBrush of type string.

the Problem is: the property is already using get & set to & from the dependency-property.

suggested this approach to ChatGPT: So I changed the dependency-property to serializedBrush string

public class CategoryModel : UserControl{
    ...
    public Brush Color
    {
        get { return JsonSerializer.Deserialize<Brush>(SerializedBrush); }
        set { SerializedBrush = JsonSerializer.Serialize(value); }
    }

    public static readonly DependencyProperty SerializedBrush=
    DependencyProperty.Register("Color", typeof(string), typeof(CategoryModel));
}

AI comment: don't use dependency property to interact with the database, it is used more to deal with the business logic, and gave me the following solution

using System.ComponentModel.DataAnnotations.Schema;
using System.Windows;
using System.Windows.Media;
using System.Text.Json;

namespace YourNamespace
{
    public class CategoryModel : DependencyObject
    {
        
        public static readonly DependencyProperty SerializedBrushProperty =
            DependencyProperty.Register("SerializedBrush", typeof(string), typeof(CategoryModel));
        [Column(TypeName = "nvarchar(max)")] // Specify column type for EF
        public string SerializedBrush
        {
            get { return (string)GetValue(SerializedBrushProperty); }
            set { SetValue(SerializedBrushProperty, value); }
        }

        public Brush Color
        {
            get { return JsonSerializer.Deserialize<Brush>(SerializedBrush); }
            set { SerializedBrush = JsonSerializer.Serialize(value); }
        }
    }
}

but what about the dependency property of the Brush Color


Solution

  • adding another property to be used for serialization or change the color to RGB
    for
    a property that has < dependency-property > related to it, is the cause/source of the problem.
    because you will then have 3 properties that you need to somehow identify the relation (getters & setters) between them.

    Solution : we got 2 options:

    First: use Value Conversion in the "OnModelCreating()" method in the DbContext.

    you can do that in the model class (CategoryModel)

    using System.ComponentModel.DataAnnotations.Schema;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    public class CategoryModel : UserControl{
    ...
        [Column(TypeName = "nvarchar(24)")] // EF8 will automatically pick the pre-configured conversion method for it.
        public Brush Color
        {
            get { return (Brush)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }
    
        public static readonly DependencyProperty ColorProperty =
        DependencyProperty.Register("Color", typeof(Brush), typeof(CategoryModel), new PropertyMetadata(Brushes.Black));
    ...
    }
    

    Or in the DbContext OnModelCreating() method

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<CategoryModel>()
            .Property(e => e.Color)
            .HasConversion<string>();
    }
    

    Second: leverage Entity Framwork Core 8's ability to store complex types as JSON. (might provide the solution for it later)

    Thank you everyone, and special thanks to Jeremy Lakeman.