元素 'id' 不匹配任何字段或 属性 嵌套 类 错误
Element 'id' does not match any field or property of error with nested classes
我有以下 mongodb 文档架构;
{
"_id" : ObjectId("5c9d34ff781318afb9e8ab43"),
"name" : "Name",
"slug" : "slug",
"services" : {
"subservice" : {
"id" : NumberInt(37030)
}
}
}
然后我将 classes 定义为;
public class MainModel
{
public ObjectId Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("slug")]
public string Slug { get; set; }
[BsonElement("services")]
public ServicesDef Services { get; set; }
public class ServicesDef
{
[BsonElement("subservice")]
public SubServiceDef SubService{ get; set; }
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
}
}
}
但是当我查询文档时不知何故;
var result = await Repository.FindAsync(x => x.Slug == slug);
services.subservice.id 未正确注册并获得
元素 'id' 与 class SubServiceDef 的任何字段或 属性 不匹配。
卡在这里并寻求建议。
我想我遇到了与 cannot deserialize with the "Id" attribute 相同的问题,但似乎还有解决方案。
长话短说:一切都与约定有关。 MongoDB .NET 驱动程序公开静态 class ConventionRegistry
允许您注册自己的约定(更多 here). Additionally there are two "built-in" conventions __defaults__
and __attributes__
. Digging deeper (driver github)您会发现它注册了一个非常有趣的约定:
new NamedIdMemberConvention(new [] { "Id", "id", "_id" })
这意味着 id
成员将被视为常规 BSON _id 元素。
如何解决?
您可以摆脱默认约定
ConventionRegistry.Remove("__defaults__");
然而,您将自动放弃所有其他非常危险的驱动程序约定。或者,您可以创建一个始终为空的假 属性:
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
[BsonId]
public ObjectId FakeId { get; set; }
}
或者您可以只使用 BsonNoId
属性 which
Specifies that the class's IdMember should be null.
[BsonNoId]
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
}
因此约定会将您的 id
设置为 class 映射中的 IdMember,但随后在后处理过程中,此属性将强制 IdMember 为空,并且您的 class 将成功反序列化
我喜欢@mickl 的回答。我遇到的问题是无法更新模型和添加属性。我还需要原始的 Id
s 而不是反序列化后的 null
s。
我尝试了 BsonClassMap
但我有太多的子模型要更新。
所以,我最终采用了你的想法,删除了默认约定。
public class MongoDbDefaultConventionPack : IConventionPack
{
// private static fields
private static readonly IConventionPack __defaultConventionPack = new MongoDbDefaultConventionPack();
// private fields
private readonly IEnumerable<IConvention> _conventions;
// constructors
/// <summary>
/// Initializes a new instance of the <see cref="MongoDbDefaultConventionPack" /> class.
/// </summary>
private MongoDbDefaultConventionPack()
{
_conventions = new List<IConvention>
{
new ReadWriteMemberFinderConvention(),
// new NamedIdMemberConvention(new [] { "Id", "id", "_id" }), changed to:
new NamedIdMemberConvention(),
new NamedExtraElementsMemberConvention(new [] { "ExtraElements" }),
// new IgnoreExtraElementsConvention(false), changed to:
new IgnoreExtraElementsConvention(true),
new ImmutableTypeClassMapConvention(),
new NamedParameterCreatorMapConvention(),
new StringObjectIdIdGeneratorConvention(), // should be before LookupIdGeneratorConvention
new LookupIdGeneratorConvention()
};
}
// public static properties
/// <summary>
/// Gets the instance.
/// </summary>
public static IConventionPack Instance
{
get { return __defaultConventionPack; }
}
// public properties
/// <summary>
/// Gets the conventions.
/// </summary>
public IEnumerable<IConvention> Conventions
{
get { return _conventions; }
}
}
然后替换配置:
ConventionRegistry.Remove("__defaults__");
ConventionRegistry.Register("__defaults__", MongoDbDefaultConventionPack.Instance, t => true);
作为默认约定,在我的案例中效果很好。没有更多的例外。可用的原始 ID
我有以下 mongodb 文档架构;
{
"_id" : ObjectId("5c9d34ff781318afb9e8ab43"),
"name" : "Name",
"slug" : "slug",
"services" : {
"subservice" : {
"id" : NumberInt(37030)
}
}
}
然后我将 classes 定义为;
public class MainModel
{
public ObjectId Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("slug")]
public string Slug { get; set; }
[BsonElement("services")]
public ServicesDef Services { get; set; }
public class ServicesDef
{
[BsonElement("subservice")]
public SubServiceDef SubService{ get; set; }
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
}
}
}
但是当我查询文档时不知何故;
var result = await Repository.FindAsync(x => x.Slug == slug);
services.subservice.id 未正确注册并获得
元素 'id' 与 class SubServiceDef 的任何字段或 属性 不匹配。
卡在这里并寻求建议。
我想我遇到了与 cannot deserialize with the "Id" attribute 相同的问题,但似乎还有解决方案。
长话短说:一切都与约定有关。 MongoDB .NET 驱动程序公开静态 class ConventionRegistry
允许您注册自己的约定(更多 here). Additionally there are two "built-in" conventions __defaults__
and __attributes__
. Digging deeper (driver github)您会发现它注册了一个非常有趣的约定:
new NamedIdMemberConvention(new [] { "Id", "id", "_id" })
这意味着 id
成员将被视为常规 BSON _id 元素。
如何解决?
您可以摆脱默认约定
ConventionRegistry.Remove("__defaults__");
然而,您将自动放弃所有其他非常危险的驱动程序约定。或者,您可以创建一个始终为空的假 属性:
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
[BsonId]
public ObjectId FakeId { get; set; }
}
或者您可以只使用 BsonNoId
属性 which
Specifies that the class's IdMember should be null.
[BsonNoId]
public class SubServiceDef
{
[BsonElement("id")]
public int Id { get; set; }
}
因此约定会将您的 id
设置为 class 映射中的 IdMember,但随后在后处理过程中,此属性将强制 IdMember 为空,并且您的 class 将成功反序列化
我喜欢@mickl 的回答。我遇到的问题是无法更新模型和添加属性。我还需要原始的 Id
s 而不是反序列化后的 null
s。
我尝试了 BsonClassMap
但我有太多的子模型要更新。
所以,我最终采用了你的想法,删除了默认约定。
public class MongoDbDefaultConventionPack : IConventionPack
{
// private static fields
private static readonly IConventionPack __defaultConventionPack = new MongoDbDefaultConventionPack();
// private fields
private readonly IEnumerable<IConvention> _conventions;
// constructors
/// <summary>
/// Initializes a new instance of the <see cref="MongoDbDefaultConventionPack" /> class.
/// </summary>
private MongoDbDefaultConventionPack()
{
_conventions = new List<IConvention>
{
new ReadWriteMemberFinderConvention(),
// new NamedIdMemberConvention(new [] { "Id", "id", "_id" }), changed to:
new NamedIdMemberConvention(),
new NamedExtraElementsMemberConvention(new [] { "ExtraElements" }),
// new IgnoreExtraElementsConvention(false), changed to:
new IgnoreExtraElementsConvention(true),
new ImmutableTypeClassMapConvention(),
new NamedParameterCreatorMapConvention(),
new StringObjectIdIdGeneratorConvention(), // should be before LookupIdGeneratorConvention
new LookupIdGeneratorConvention()
};
}
// public static properties
/// <summary>
/// Gets the instance.
/// </summary>
public static IConventionPack Instance
{
get { return __defaultConventionPack; }
}
// public properties
/// <summary>
/// Gets the conventions.
/// </summary>
public IEnumerable<IConvention> Conventions
{
get { return _conventions; }
}
}
然后替换配置:
ConventionRegistry.Remove("__defaults__");
ConventionRegistry.Register("__defaults__", MongoDbDefaultConventionPack.Instance, t => true);
作为默认约定,在我的案例中效果很好。没有更多的例外。可用的原始 ID