简体   繁体   中英

Entity Framework custom type as property

I have a custom type like:

    public class Date
    {
        public int Year {get; }
        public int Month {get; }
        public int Day {get; }

        private Date(int year, int month, int day)
        {
            // ... Year = year, Month = month, Day = day
        }

        public static Date Of(string pattern) {
           // ... to parse from pattern
           // return new Date(year, month, date);
        }

        public override string ToString(){
           // ... string like "2020-02-02"
        }
    }
}

I want to use it in a Entity to store it in database as string:

public class Student{
      public string Name{get; set; }
      public Date CreateDate{get; set; }
      public DateTime CreateDate2{get; set; }
}

I have a DateConverter to covert the Date object to string:

    class DateConverter : ValueConverter<Date, string>
    {
        public DateConvertor(ConverterMappingHints? mappingHints = null) :
            base(date => date.ToString(), s => Date.Of(s), mappingHints)
        {
        }
    }

But I could not apply the DateConvertor.

EF Core treat Date as an Entity Type, instead of a property of an Entity.

That means:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
            {
                // "Date" appears here as an Entity
                _logger.Info("Model Entity: {0}", entityType);
                foreach (IMutableProperty property in entityType.GetProperties())
                {
                     // I want "Date" appears here as a property.
                     // Actually "DateTime CreateDate2" appears here.
                     // I want my "Date" to act like "DateTime"

How to make custom type Date act like a DateTime as a property, instead of a entity type?

Or

How to apply DateConverter to my Date ?


Update: This is one of the examples.
Sorry, I could not share my real code because they belong to my company.

But the problem is the same.

I want to know how to handle all this kind of problems.
What if I have a Metadata, to store it as string (or number) in database?

    public class Metadata {
        public int Field1 {get; }
        public string Filed2 {get; }
        public double Field3 {get; }
        
        private Metadata(int xxx /* other params */ )
        {
            // to assign all
        }

        public static Metadata Parse (string pattern) {
           // ... to parse from pattern
           // return new Metadata(xxx);
        }

        public override string ToString(){
           // ... string like "abc.id]afe[dfe]fefa"
           // using a special encoding
        }
    }

    class MetadataConverter : ValueConverter<Metadata, string>
    {
        public MetadataConverter(ConverterMappingHints? hints = null) :
            base(data => data.ToString(), data => Metadata.Parse(data), mappingHints)
        {
        }
    }

EF Core treat Date as an Entity Type, instead of a property of an Entity.

Only in this situation could I use DateTime instead, no problem. But could I find out an alternate solution every time?

Rather than convert it to a DateTime, which may work in this case but not all cases, you can register your value object as a complex type

This means that EF will interpret your Date object as a "bag of properties" of the Student object that owns it, rather than as a separate entity of its own. In short, it will create a table column (in the parent entity table, eg [Students] ) for every public property (day, month, year).

However, that does come with the requirement of needing to have setters on your properties and a parameterless constructor, otherwise EF cannot render your value object from the database.

In cases where there is no equivalent data type that EF can handle (such as DateTime for Date ), this is the better option.

Just configure the ValueConverter in OnModelCreating, like this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

    base.OnModelCreating(modelBuilder);

    var dateConverter = new ValueConverter<Date, string>(
        v => v.ToString(),
        s => Date.Parse(s)
      ); 
    foreach (var et in modelBuilder.Model.GetEntityTypes())
    {
        foreach (var prop in et.GetProperties().Where(prop => prop.ClrType == typeof(Date)))
        {
            prop.SetValueConverter(dateConverter);
            //modelBuilder.Entity(et.Name).Property(prop.Name).HasConversion(dateConverter);
        }
        
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM