Search code examples
c#entity-frameworkobservablecollectioninotifycollectionchanged

Serializing Class for Entity Database Storage


I have an atomic class I'm using to flag days of the week as true/false values.

public class DaysOfWeek
{
    public bool Sunday { get; set; }
    public bool Monday { get; set; }
    public bool Tuesday { get; set; }
    public bool Wednesday { get; set; }
    public bool Thursday { get; set; }
    public bool Friday { get; set; }
    public bool Saturday { get; set; }

    public bool this[string day]
    {
        get
        {
            return (bool)GetType().GetProperty(day).GetValue(this, null);
        }
        set
        {
            GetType().GetProperty(day).SetValue(this, value);
        }
    }
}

I'd like to store this using Entity as a single column. I have a POCO that looks like this:

public class SSRS_Subscription
{
    [Key]
    public Guid id { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public Recurrence RecurrencePattern { get; set; }
    public DateTime StartTime { get; set; }
    public int? MinuteInterval { get; set; }
    public int? DaysInterval { get; set; }
    public int? WeeksInterval { get; set; }
    [NotMapped]
    public DaysOfWeek DaysOfWeek
    {
        get
        {
            return SerializeHelper.DeserializeJson<DaysOfWeek>(internalDaysOfWeek);
        }
        set
        {
            internalDaysOfWeek = SerializeHelper.SerializeJson(value);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    [Column("DaysOfWeek")]
    public string internalDaysOfWeek { get; set; }

    public SSRS_Subscription()
    {
        DaysOfWeek = new DaysOfWeek();
    }
}

The issue here is that when I access the DaysOfWeek property, I cannot set a value.

var testSub = new SSRS_Subscription();
testSub.DaysOfWeek.Friday = true;
// testSub.DaysOfWeek.Friday stays false (the default value)

// However doing this sets the correct value...
var tmpDaysOfWeek = testSub.DaysOfWeek;
tmpDaysOfWeek.Friday = true;
testSub.DaysOfWeek = tmpDaysOfWeek;

I believe what I need is an ObservableCollection event, but after searching for examples, I'm not exactly sure how to implement it. Do I modify my Entity POCO SSRS_Subscription to add it? Any hints or tips on how to do this better would be greatly appreciated.


Solution

  • This was the solution I came up with... I created an ISerialize interface then had my POCO implement it...

    public interface ISerialize
    {
        void Serialize();
    }
    
    public class SSRS_Subscription : ISerialize
    {
        [Key]
        public Guid id { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime? EndDate { get; set; }
        public Recurrence RecurrencePattern { get; set; }
        public int? MinuteInterval { get; set; }
        public int? DaysInterval { get; set; }
        public int? WeeksInterval { get; set; }
        [NotMapped]
        public DaysOfWeek DaysOfWeek { get; set; }
    
        [Column("DaysOfWeek")]
        private string internalDaysOfWeek { get; set; }
    
        [NotMapped]
        public MonthsOfYear MonthsOfYear { get; set; }
    
    
        [Column("MonthsOfYear")]
        private string internalMonthsOfYear { get; set; }
    
        public Catalog_Reports_Subscription()
        {
            DaysOfWeek = new DaysOfWeek();
            MonthsOfYear = new MonthsOfYear();
        }
    
        public WhichWeek? MonthWhichWeek { get; set; }  
    
        public string Days { get; set; }
    
        public void Serialize()
        {
            internalDaysOfWeek = SerializeHelper.SerializeJson(DaysOfWeek);
            internalMonthsOfYear = SerializeHelper.SerializeJson(MonthsOfYear);
        }
    
        public class Configuration : EntityTypeConfiguration<SSRS_Subscription>
        {
            public Configuration()
            {
                Property(s => s.internalDaysOfWeek).HasColumnName("DaysOfWeek");
                Property(s => s.internalMonthsOfYear).HasColumnName("MonthsOfYear");
            }
        }
    }
    

    Then I made the following changes to my DbContext:

       public ReportingDbContext() : base("ReportingDbContext")
        {
            var objectContext = ((IObjectContextAdapter)this).ObjectContext;
            objectContext.SavingChanges += new EventHandler(OnSavingChanges);
        }
    
        public void OnSavingChanges(object sender, EventArgs e)
        {
            foreach (ObjectStateEntry entry in
                ((ObjectContext)sender).ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
            {
                if (!entry.IsRelationship && (entry.Entity is ISerialize))
                {
                    (entry.Entity as ISerialize).Serialize();
                }
            }
        }
    

    Whenever SaveChanges is called on my context, SavingChanges runs prior, looks for any object that implements ISerialize and calls the Serialize function which takes the non-entity mapped properties and serializes them into JSON (in my case) and stores them in the mapped string properties that represent them.