【问题标题】:Entity framework serialization multiple properties to one column实体框架将多个属性序列化到一列
【发布时间】:2016-01-11 05:22:13
【问题描述】:

我想将以下类映射到一个表,使用实体框架,最好使用流利的 api。

public class MyEntity
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int Age {get;set;}
    public string OtherData {get;set;}
    public List<Blabla> BlaBlaList {get;set;}
}

表我的实体:

column Id
column Name
column SerializedData

是否可以仅将 Id 和 Name 映射到列,以及在“SerializedData”列中序列化的所有其他属性?

如果不是“仅”其他属性,整个对象也可以在 SerializedData 列中序列化

谢谢, 史蒂文

【问题讨论】:

  • 您希望将来自所有属性的数据合并并存储到一列中?

标签: c# sql-server entity-framework serialization


【解决方案1】:

另一个类似于 Drew 的回答是:

public class MyEntity : IMySerializable
{
  public int Id {get;set;}
  public string Name {get;set;}

  [NotMapped]
  public int Age {get;set;}
  [NotMapped]
  public string OtherData {get;set;}
  [NotMapped]
  public List<Blabla> BlaBlaList {get;set;}

  public byte[] SerializedData  
  {
    get
    {
      return this.MySerialize();
    } 
    set 
    {
      this.MyDeserialize(value);
    }
  }
}

然后是一种扩展方法,允许您对多个实体执行此操作:

public static IMySerializableExtensions
{
  public static byte[] MySerialize<T>(this T instance)
    where T : IMySerializable
  {
    byte[] result = // ...

    // code

    return result;
  }

  public static void MyDeserialize<T>(this T instance, byte[] value)
    where T : IMySerializable
  {
     // deserialize value and update values
  }
}

您可以找出要反序列化/序列化的属性,因为它们上面会有NotMappedAttribute

【讨论】:

    【解决方案2】:

    你必须自己做......

    我建议为您的数据库映射创建一个单独的类,并将“MyEntity”保留为 POCO。这最终取决于偏好,但我更喜欢让我的实体尽可能接近数据库结构。这种方式更容易维护。

    因此,话虽如此,创建一个单独的类,它是您将实际与之交互的对象,并为其提供一个实例方法来序列化自身,以及一个用于反序列化的静态方法。我在这里使用了 JSON,但你可以做任何你想做的事情。请注意,我还添加了一种将其转换为 MyDBEntity 的方法:您的逻辑可能在其他地方,但这应该让您了解如何执行此操作。

    public class MyEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string OtherData { get; set; }
        public List<int> BlaBlaList { get; set; }
    
        public byte[] Serialize()
        {
            string json = JsonConvert.SerializeObject(this);
            return Encoding.ASCII.GetBytes(json);
        }
    
        public static string Deserialize(byte[] objectBytes)
        {
            return Encoding.ASCII.GetString(objectBytes);
        }
    
        public MyDBEntity ConvertToDBEntity()
        {
            MyDBEntity dbEntity = new MyDBEntity();
            dbEntity.ID = Id;
            dbEntity.Name = Name;
            dbEntity.SerializedData = this.Serialize();
            return dbEntity;
        }
    }
    
    public class MyDBEntity
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public byte[] SerializedData { get; set; }
    }
    

    接下来,将 MyDBEntity 类添加到您的上下文中:

    public class EFContext : DbContext
    {
        public DbSet<MyDBEntity> Entities { get; set; }
    }
    

    就是这样!现在你可以做类似的事情了

     using (var db = new EFContext())
        {
            MyEntity me = new MyEntity();
            me.Name = "Bob";
            me.Age = 25;
            me.OtherData = "he does stuff";
            me.BlaBlaList = new List<int> { 7, 8, 9 };
            MyDBEntity newEntity = me.ConvertToDBEntity();
    
            db.Entities.Add(newEntity);
            db.SaveChanges();
        }
    

    我为这个答案设计了一个小控制台应用程序,如果你愿意,我把它放在Github 上。

    【讨论】:

      【解决方案3】:

      虽然这个问题是针对 Entity Framework 提出的,但我有完全相同的问题,但针对 Entity Framework Core。事实证明,EF Core 有一种更优雅的方法来将序列化数据存储在单个列中,同时允许单个属性存在于域模式中。更优雅,因为它不需要对领域模型本身进行任何更改。

      是这样的:

      您的实体保持原样:

      public class MyEntity
      {
          public int Id {get;set;}
          public string Name {get;set;}
          public int Age {get;set;}
          public string OtherData {get;set;}
          public List<Blabla> BlaBlaList {get;set;}
      }
      

      然后配置您的模型以忽略您不想映射到单个列的属性,并添加一个 shadow 属性:

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
          modelBuilder.Ignore(x => x.Age);
          modelBuilder.Ignore(x => x.OtherData);
          modelBuilder.Ignore(x => x.BlaBlaList);
      
          // Adding a "shadow" property called "Data".
          modelBuilder.Property<string>("Data");
      }
      

      当您现在保存实体时,您可以简单地将所需的属性序列化为 JSON 字符串并设置“数据”影子属性,如下所示:

      var entity = new MyEntity { ... };
      
      var data = new
      {
         entity.Age,
         entity.OtherData,
         entity.BlaBlaList
      };
      
      var json = JsonConvert.Serialize(data);
      
      _dbContext.Property("Data").CurrentValue = json;
      

      当从存储中加载您的实体时,请确保重新水合属性:

      var entity = await _dbContext.MyEntities.FirstOrDefaultAsync(...);
      
      // Simply re-constructing the anonymous type for deserialization. It's not necessary to actually initialize each field with the current values (which are empty anyway), but this is just a convenient way to model the anonymous type.
      
      var data = new
      {
         entity.Age,
         entity.OtherData,
         entity.BlaBlaList
      };
      
      var json = _dbContext.Property("Data").CurrentValue = json;
      data = JsonConvert.DeserializeAnonymousType(json, data);
      
      entity.Age = data.Age;
      entity.OtherData = data.OtherData;
      entity.BlaBlaList = data.BlaBlaList;
      

      就是这样。 EF Core 允许您通过利用其新的影子属性功能将您的域模型用作纯粹、干净的 POCO。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-20
        • 1970-01-01
        • 1970-01-01
        • 2014-12-05
        • 1970-01-01
        • 2012-02-08
        • 2014-09-29
        • 1970-01-01
        相关资源
        最近更新 更多