简体   繁体   English

MongoDB Custom Serializer 避免 _t 被添加集合,抛出 ReadEndArray 错误?

[英]MongoDB Custom Serializer to avoid _t being added collection, throws ReadEndArray Error?

Situation: Language: C# using the C# Driver I have a model that contains a List as a property.情况:语言:使用 C# 驱动程序的 C# 我有一个模型,其中包含一个 List 作为属性。 That List can contain one of 3 different models that all inherit the BaseModelClass.该列表可以包含全部继承 BaseModelClass 的 3 个不同模型之一。 To assist in serialization of this situation Mongo adds _t to identify which of the models is actually being used.为了帮助序列化这种情况,Mongo 添加了 _t 来识别实际使用的模型。 For us this is a problem due to the amount of space that _t is taking up.对我们来说,这是一个问题,因为 _t 占用的空间量很大。 I am a lowly dev, I have asked for more space and ram and they have told me to solve it without the additional space.我是一个低级的开发人员,我要求更多的空间和内存,他们告诉我在没有额外空间的情况下解决它。 So I sat down to writing a custom serializer that handled the different types without writing a _t to the BSONDocument.所以我坐下来编写一个处理不同类型的自定义序列化程序,而无需将 _t 写入 BSONDocument。 I thought all was great until I started doing my unit testing of the serialization.在我开始对序列化进行单元测试之前,我认为一切都很好。 I started getting "ReadEndArray can only be called when ContextType is Array, not when ContextType is Document."我开始收到“只能在 ContextType 为 Array 时调用 ReadEndArray,而不能在 ContextType 为 Document 时调用。”

Any advice or suggestions are greatly appreciated.非常感谢任何意见或建议。

Here is the code I have thus far...这是我到目前为止的代码......

<---------Collection Model---------------------> <---------收藏模型--------->

[BsonCollectionName("calls")]
[BsonIgnoreExtraElements]
public class Call
{
    [BsonId]
    public CallId _id { get; set; }

    [BsonElement("responses")]
    [BsonIgnoreIfNull]
    public IList<DataRecord> Responses { get; set; }
}

Also asked here: https://groups.google.com/forum/#!topic/mongodb-user/iOeEXbUYbo4 此处还询问: https//groups.google.com/forum/#!topic / mongodb-user / iOeEXbUYbo4

I think your better bet in this situation is to use a custom discriminator convention. 我认为在这种情况下你最好的选择是使用自定义鉴别器约定。 You can see an example of this here: https://github.com/mongodb/mongo-csharp-driver/blob/v1.x/MongoDB.DriverUnitTests/Samples/MagicDiscriminatorTests.cs . 你可以在这里看到一个例子: https//github.com/mongodb/mongo-csharp-driver/blob/v1.x/MongoDB.DriverUnitTests/Samples/MagicDiscriminatorTests.cs While this example is based on whether a field exists in the document, you could easily base it on what type the field is (BsonType.Int32, BsonType.Date, etc...). 虽然此示例基于文档中是否存在字段,但您可以轻松地将其基于字段的类型(BsonType.Int32,BsonType.Date等...)。

Basing on @Craig Wilson answer, to get rid off all discriminators, you can: 基于@Craig Wilson回答,为了摆脱所有歧视者,你可以:

public class NoDiscriminatorConvention : IDiscriminatorConvention
    {
        public string ElementName => null;

        public Type GetActualType(IBsonReader bsonReader, Type nominalType) => nominalType;

        public BsonValue GetDiscriminator(Type nominalType, Type actualType) => null;
    }

and register it: 并注册:

BsonSerializer.RegisterDiscriminatorConvention(typeof(BaseEntity), new NoDiscriminatorConvention());

This problem occurred in my case when I was adding a Dictionary<string, object> and List entities to database.当我将 Dictionary<string, object> 和 List 实体添加到数据库时,就出现了这个问题。 The following link helped me in this regard: C# MongoDB complex class serialization .以下链接在这方面帮助了我: C# MongoDB complex class serialization For your case, I would suggest, following the link given above, as follows:对于您的情况,我建议按照上面给出的链接,如下所示:


using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

[JsonConverter(typeof(DataRecordConverter))]
public abstract class DataRecord
{
    public string Key { get; set; }
    public string DataRecordType {get;}
}

public class DataRecordInt : DataRecord
{
    public int Value { get; set; }
    public override string DataRecordType => "Int"
}

public class DataRecordDateTime : DataRecord
{
    public DateTime? Value { get; set; }
    public override string DataRecordType => "DateTime"
}


public class DataRecordConverter: JsonConverter
{
  public override bool CanWrite => false;
  public override bool CanRead => true;
  
  public override bool CanConvert(Type objectType)
  {
     return objectType == typeof(DataRecord);
  }
 
  public override void WriteJson(
              JsonWriter writer, 
              object value, 
              JsonSerializer serializer)
  {}

  public override object ReadJson(
              JsonReader reader,
              Type objectType,
              object existingValue,
              JsonSerializer serializer)
  {
     var jsonObject = JObject.Load(reader);
     var dataRecord = default(DataRecord);

     switch (jsonObject["DataRecordType"].Value<string>())
     {
         case "Int":
            dataRecord = new DataRecordInt();
            break;
         case "DateTime":
            dataRecord = new DataRecordDataTime();
            break;

     }

     serializer.Populate(jsonObject.CreateReader, dataRecord);
     return dataRecord;
  }
}

[BsonCollectionName("calls")]
[BsonIgnoreExtraElements]
public class Call
{
    [BsonId]
    public CallId _id { get; set; }

    [JsonIgnore]
    [BsonElement("responses")]
    [BsonIgnoreIfNull]
    public BsonArray Responses { get; set; }
}

You can add populate the BsonArray using:您可以使用以下方法添加填充 BsonArray:

var jsonDoc = JsonConvert.SerializeObject(source);
var bsonArray = BsonSerializer.Deserialize<BsonArray>(jsonDoc);

Now, you can get deserialized List from Mongo using:现在,您可以使用以下方法从 Mongo 获取反序列化列表:

var bsonDoc = BsonExtensionMethods.ToJson(source);
var dataRecordList = JsonConvert.DeserializeObject<List<DataRecord>>(bsonDoc, new DataRecordConverter())

Hope this helps, again, thanks to C# MongoDB complex class serialization for this.希望这有助于再次感谢C# MongoDB 复杂类序列化

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

相关问题 MongoDb 自定义集合序列化器 - MongoDb custom collection serializer 使用自定义Json序列化器创建集合 - Creating a collection with custom Json serializer MongoDB 自定义序列化程序未设置属性 - MongoDB Custom Serializer not setting properties 为MongoDB自定义序列化器添加序列化信息 - Adding serialization information for MongoDB custom serializer 实体未添加到另一个实体集合 - Entity not being added to another entities collection MongoDB驱动程序无法在通过ID过滤期间将自定义序列化程序转换为IBsonSerializer - MongoDB driver unable cast custom serializer to IBsonSerializer during filter by Id 如何结合使用LINQ和自定义序列化器? (MONGODB C#) - How to use/enable LINQ combined with custom serializer? (MONGODB C#) UI元素添加到控件集合时会引发异常 - UI Element throws exception when added to control-collection 自定义序列化程序,可为MongoDb处理可为空和不能为空的类型 - Custom serializer that processes both nullable and not nullable types for MongoDb 在 MongoDB 中为嵌套的 object 使用自定义序列化程序会干扰使用该 object 的过滤器 - Using a custom serializer in MongoDB for a nested object interferes with filters using that object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM