有没有办法完全禁用(对于所有类)将鉴别器(“_t”)字段添加到 bson 文档中?我指的是:mongo-csharp-driver/多态性
假设我们有一个Square和Rectangle继承自Shape。
public abstract class Shape
{
public ObjectId Id { get; set; }
}
public sealed class Square : Shape
{
public int Size { get; set; }
}
public sealed class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
就像你说的,如果我们运行以下代码。
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
Run Code Online (Sandbox Code Playgroud)
我们将把以下内容插入到 MongoDB 中
db.shapes.find()
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0b"), "_t" : "Square", "Size" : 10 }
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0c"), "_t" : "Rectangle", "Width" : 4, "Height" : 5 }
Run Code Online (Sandbox Code Playgroud)
最初,我认为我们能够DiscriminatorIsRequired在 上设置标志BsonClassMap并将其包装在约定中,但是,通过尝试此操作,由于 MongoDB C# 驱动程序中的以下逻辑位,它似乎失败了。
private bool ShouldSerializeDiscriminator(Type nominalType)
{
return (nominalType != _classMap.ClassType || _classMap.DiscriminatorIsRequired || _classMap.HasRootClass) && !_classMap.IsAnonymous;
}
Run Code Online (Sandbox Code Playgroud)
因此,因为我们无法告诉序列化器我们不想包含鉴别器,所以我们必须给它一个约定,而不是不执行任何操作。如果我们创建一个IDiscriminatorConvention几乎不执行任何操作并为鉴别器返回 null 的值,那么驱动程序不会将其添加到文档中。
public class NullDiscriminatorConvention : IDiscriminatorConvention
{
public static NullDiscriminatorConvention Instance { get; }
= new NullDiscriminatorConvention();
public Type GetActualType(IBsonReader bsonReader, Type nominalType)
=> nominalType;
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
=> null;
public string ElementName { get; } = null;
}
Run Code Online (Sandbox Code Playgroud)
然后需要针对每种类型注册该鉴别器约定。
BsonSerializer.RegisterDiscriminatorConvention(typeof(Square), NullDiscriminatorConvention.Instance);
BsonSerializer.RegisterDiscriminatorConvention(typeof(Rectangle), NullDiscriminatorConvention.Instance);
Run Code Online (Sandbox Code Playgroud)
或者,如果我们希望它适用于所有类型,您可以做一些反思。
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => @t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => @t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我们重新运行我们的代码。
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => @t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => @t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
Run Code Online (Sandbox Code Playgroud)
我们将得到预期的输出。
db.shapes.find()
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d36"), "Size" : 10 }
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d37"), "Width" : 4, "Height" : 5 }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1765 次 |
| 最近记录: |