实体框架自定义类型作为属性

时间:2020-07-08 09:27:40

标签: c# .net entity-framework .net-core entity-framework-core

我有一个自定义类型,例如:

    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"
        }
    }
}

我想在实体中使用它以字符串形式将其存储在数据库中:

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

我有一个DateConverter可以将Date对象转换为字符串:

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

但是我无法应用DateConvertor。

EF核心将日期视为实体类型,而不是实体的属性。

这意味着:

        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"

如何使自定义类型DateDateTime一样充当属性,而不是实体类型?

如何将DateConverter应用于我的Date


更新:这是示例之一。
抱歉,我无法共享我的真实代码,因为它们属于我的公司。

但是问题是相同的。

我想知道如何处理所有这类问题。
如果我有一个元数据,将其作为字符串(或数字)存储在数据库中怎么办?

    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)
        {
        }
    }

2 个答案:

答案 0 :(得分:2)

EF核心将日期视为实体类型,而不是实体的属性。

只有在这种情况下,我才可以使用DateTime代替,没问题。但是我每次都能找到替代解决方案吗?

您可以将值对象注册为complex type

,而不是将其转换为DateTime(在这种情况下但并非在所有情况下都可以使用),

这意味着EF将把您的Date对象解释为拥有它的Student对象的“属性包”,而不是将其解释为一个单独的实体。简而言之,它将为每个公共财产(天,月,年)创建一个表列(在父实体表,例如[Students]中)。

但是,这确实需要在属性上使用setter和无参数构造函数,否则EF无法从数据库中呈现您的值对象。

在没有EF可以处理的等效数据类型的情况下(例如DateTime的{​​{1}}),这是更好的选择。

答案 1 :(得分:0)

只需在OnModelCreating中配置ValueConverter,如下所示:

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);
        }
        
    }
}