目的,实现使用Mongodb.Driver查询获取数据时,实现字段的自定义(类型转换,值运算等)
实现方式
实现 IBsonMemberMapAttribute 特性类,在实现类中Apply 方法中设置自定义 IBsonSerializer 实现。然后在数据接收类中,给需要自定义反序列化方式的字段上添加实现的IBsonMemberMapAttribute特性。
一、示例代码
1.实现IBsonMemberMapAttribute
代码如下(示例):
using System;
using log4net;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
namespace Test.Entity.Attribute
{
//自定义mogndb bson 字段特性类
public class BsonFieldConverterAttribute : System.Attribute, IBsonMemberMapAttribute
{
public void Apply(BsonMemberMap memberMap)
{
memberMap.SetSerializer(new MileageBsonSerializer());
}
}
/// <summary>
/// 自定义mongdob bson 序列化解析器类
/// mongodb 序列化 兼容处理
/// </summary>
public class MileageBsonSerializer : IBsonSerializer
{
private static readonly ILog log = LogManager.GetLogger(nameof(MileageBsonSerializer));
public Type ValueType => typeof(double?);
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
IBsonReader reader = context.Reader;
BsonType currentBsonType = reader.GetCurrentBsonType();
switch (currentBsonType)
{
case BsonType.String:
string value = reader.ReadString();
return GetValue(value);
case BsonType.Double:
return reader.ReadDouble();
case BsonType.Null:
reader.SkipValue();// 缺少 解析数据时会报错
return -1d;
default:
log.Error("MileageBsonSerializer 反序列化不包含类型:" + currentBsonType.ToString());
reader.SkipValue();// 缺少 解析数据时会报错
return -1d;
}
throw CreateCannotDeserializeFromBsonTypeException(currentBsonType);
}
protected Exception CreateCannotDeserializeFromBsonTypeException(BsonType bsonType)
{
return new FormatException($"Cannot deserialize a '{BsonUtils.GetFriendlyTypeName(ValueType)}' from BsonType '{bsonType}'.");
}
private double GetValue(string value)
{
if (value != null & value is string
&& !string.IsNullOrWhiteSpace(value)
&& (value).Contains("Km")
&& (value).Contains("-")
)
{
string[] arr = (value).Replace("Km", "").Split('-');
if (arr.Length > 1
&& double.TryParse(arr[0], out double start)
&& double.TryParse(arr[1], out double end))
{
return (start + end) / 2;
}
}
return -1;
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
IBsonWriter writer = context.Writer;
if (value != null)
writer.WriteDouble((value as Nullable<double>) ?? -1);
else
writer.WriteNull();
}
}
2.实现IBsonSerializer
代码如下(示例):
/// <summary>
/// 自定义mongdob bson 序列化解析器类
/// mongodb 序列化 兼容处理
/// </summary>
public class MileageBsonSerializer : IBsonSerializer
{
private static readonly ILog log = LogManager.GetLogger(nameof(MileageBsonSerializer));
public Type ValueType => typeof(double?);
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
IBsonReader reader = context.Reader;
BsonType currentBsonType = reader.GetCurrentBsonType();
switch (currentBsonType)
{
case BsonType.String:
string value = reader.ReadString();
return GetValue(value);
case BsonType.Double:
return reader.ReadDouble();
case BsonType.Null:
reader.SkipValue();// 缺少 解析数据时会报错
return -1d;
default:
log.Error("MileageBsonSerializer 反序列化不包含类型:" + currentBsonType.ToString());
reader.SkipValue();// 缺少 解析数据时会报错
return -1d;
}
throw CreateCannotDeserializeFromBsonTypeException(currentBsonType);
}
protected Exception CreateCannotDeserializeFromBsonTypeException(BsonType bsonType)
{
return new FormatException($"Cannot deserialize a '{BsonUtils.GetFriendlyTypeName(ValueType)}' from BsonType '{bsonType}'.");
}
private double GetValue(string value)
{
if (value != null & value is string
&& !string.IsNullOrWhiteSpace(value)
&& (value).Contains("Km")
&& (value).Contains("-")
)
{
string[] arr = (value).Replace("Km", "").Split('-');
if (arr.Length > 1
&& double.TryParse(arr[0], out double start)
&& double.TryParse(arr[1], out double end))
{
return (start + end) / 2;
}
}
return -1;
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
IBsonWriter writer = context.Writer;
if (value != null)
writer.WriteDouble((value as Nullable<double>) ?? -1);
else
writer.WriteNull();
}
}
}
该类命名空间与上一步相同
3.接收数据代码实体类
代码如下:
using Test.Entity.Attribute;
using MongoDB.Bson;
public class MilegaeModel
{
public ObjectId _id {set;get;}
[BsonFieldConverterAttribute]
public double? mileage {set;get;}
}
4.mongodb数据库中数据存储格式
{
"_id" : ObjectId("6596881f090dda00396d4ae3"),
"mileage" : "337.5-393.8Km",
}
总结
本文中方法主要应用场景为,mongodb 中数据字段名称没变但字段类型发生变化后,需要考虑兼容的场景下。