简体   繁体   English

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

[英]Entity framework serialization multiple properties to one column

I would like to map the following class to a table, using entity framework, preferably with fluent api.我想将以下类映射到表,使用实体框架,最好使用流畅的 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;}
}

Table MyEntity:表 MyEntity:

column Id
column Name
column SerializedData

Is it possible map only Id and Name to columns, and all other properties serialized in the "SerializedData" column?是否可以仅将 Id 和 Name 映射到列,以及在“SerializedData”列中序列化的所有其他属性?

If not "only" the other properties, the whole object may also be serialized in the SerializedData column如果不是“仅”其他属性,则整个对象也可能在 SerializedData 列中被序列化

Thanks, Steven谢谢,史蒂文

Another answer similar to Drew's answer would be to do something like:类似于德鲁的答案的另一个答案是执行以下操作:

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

Then an extension method to allow you to do this to more than one entity:然后是一种扩展方法,允许您对多个实体执行此操作:

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

You can figure out what properties to deserialize/serialize because they will have the NotMappedAttribute on them.您可以确定要反序列化/序列化的属性,因为它们将具有NotMappedAttribute

You'll have to do it yourself...你必须自己做...

I'd recommend creating a separate class for your database mapping and leaving 'MyEntity' as a POCO.我建议为您的数据库映射创建一个单独的类,并将“MyEntity”作为 POCO。 It's up to preference in the end, but I prefer to keep my entities as close as possible to the database structure.这最终取决于偏好,但我更喜欢让我的实体尽可能接近数据库结构。 It's easier to maintain that way.以这种方式维护更容易。

So, having said that, create a separate class which is the object you'll actually interact with, and give it an instance method to serialize itself, and a static method for deserialization.因此,话虽如此,创建一个单独的类,它是您将实际与之交互的对象,并为其提供一个实例方法来序列化自身,以及一个用于反序列化的静态方法。 I've used JSON here but you can do whatever you want.我在这里使用了 JSON,但你可以为所欲为。 Note I also added a method to convert it to a MyDBEntity: your logic will likely be somewhere else but this should give you an idea of how to do it.注意我还添加了一个方法来将其转换为 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; }
}

Next, add the MyDBEntity class to your context:接下来,将 MyDBEntity 类添加到您的上下文中:

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

That's about it!就是这样! now you can do stuff like现在你可以做类似的事情

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

I worked up a little console app for this answer, I put it on Github if you like.我为这个答案设计了一个小控制台应用程序,如果你愿意,我把它放在Github 上

Although this question was asked for Entity Framework, I had the exact same question but for Entity Framework Core.虽然这个问题是针对 Entity Framework 提出的,但我有完全相同的问题,但针对 Entity Framework Core。 As it turns out, EF Core has an even more elegant approach to storing serialized data in a single column while allowing individual properties to exist on the domain mode.事实证明,EF Core 有一种更优雅的方法来将序列化数据存储在单个列中,同时允许单个属性存在于域模式中。 More elegant, because it does not require any changes on the domain model itself.更优雅,因为它不需要对域模型本身进行任何更改。

It goes like this:它是这样的:

Your entity remains as-is:您的实体保持原样:

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

Then configure your model to ignore the properties you do not want to map to individual columns, and add a shadow property instead:然后配置您的模型以忽略您不想映射到单个列的属性,并添加一个阴影属性:

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

When you now save your entity, you can simply serialize the properties you want into a JSON string and set the "Data" shadow property, like this:现在保存实体时,您可以简单地将所需的属性序列化为 JSON 字符串并设置“数据”阴影属性,如下所示:

var entity = new MyEntity { ... };

var data = new
{
   entity.Age,
   entity.OtherData,
   entity.BlaBlaList
};

var json = JsonConvert.Serialize(data);

_dbContext.Property("Data").CurrentValue = json;

And when loading your entity from storage, make sure to rehydrate the properties:从存储加载实体时,请确保重新水合属性:

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;

And that's it.就是这样。 EF Core allows you to use your domain models as pure, clean POCOs by leveraging their new shadow properties feature. EF Core 允许您通过利用域模型的新阴影属性功能将域模型用作纯粹、干净的 POCO。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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