实体框架将多个属性序列化到一列

本文关键字:一列 序列化 框架 属性 实体 | 更新日期: 2023-09-27 18:17:32

我想把下面的类映射到一个表,使用实体框架,最好有流畅的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;}
}
表MyEntity:

column Id
column Name
column SerializedData

是否可能只映射Id和名称列,以及在"SerializedData"列中序列化的所有其他属性?

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

谢谢,史蒂文

实体框架将多个属性序列化到一列

另一个类似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

你得自己做……

我建议为您的数据库映射创建一个单独的类,并将'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上。

虽然这个问题是问实体框架,我有完全相同的问题,但实体框架核心。事实证明,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字符串并设置"Data"阴影属性,像这样:

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,通过利用他们的新的阴影属性特性。