Bson 직렬화사전을 BSON 에 직렬화할 때 예외 발생
저는 최근에 더 이상 사용되지 않는 v1.9에서 새로운 MongoDBC# 드라이버 v2.0으로 이동했습니다.
자, 제가 사전이 있는 수업을 연재할 때, 저는 가끔 다음과 마주칩니다.BsonSerializationException
:
몽고DB.Bson.Bson 직렬화예외:사전 표현을 사용하는 경우.문서 키 값은 문자열로 직렬화해야 합니다.
다음은 최소한의 복제품입니다.
class Hamster
{
public ObjectId Id { get; private set; }
public Dictionary<DateTime,int> Dictionary { get; private set; }
public Hamster()
{
Id = ObjectId.GenerateNewId();
Dictionary = new Dictionary<DateTime, int>();
Dictionary[DateTime.UtcNow] = 0;
}
}
static void Main()
{
Console.WriteLine(new Hamster().ToJson());
}
문제는 새 드라이버가 사전을 기본적으로 문서로 직렬화한다는 것입니다.
MongoDBC# 드라이버는 사전을 직렬화하는 세 가지 방법이 있습니다.Document
,ArrayOfArrays
&ArrayOfDocuments
(자세한 내용은 문서 참조).문서로 직렬화될 때 사전 키는 몇 가지 제한 사항이 있는 BSON 요소의 이름입니다(예: 오류에서 알 수 있듯이 문자열로 직렬화되어야 함).
이 경우 사전의 키는DateTime
s는 문자열로 직렬화되지 않지만,Date
그래서 우리는 다른 것을 선택해야 합니다.DictionaryRepresentation
.
이 특정 속성의 직렬화를 변경하려면 다음을 사용할 수 있습니다.BsonDictionaryOptions
다른 속성DictionaryRepresentation
:
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }
하지만 우리는 문제가 있는 모든 멤버들에게 개별적으로 그렇게 해야 합니다.적용 방법DictionaryRepresentation
모든 관련 회원들에게 우리는 새로운 협약을 시행할 수 있습니다.
class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
{
private readonly DictionaryRepresentation _dictionaryRepresentation;
public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation)
{
_dictionaryRepresentation = dictionaryRepresentation;
}
public void Apply(BsonMemberMap memberMap)
{
memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer()));
}
private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer)
{
var dictionaryRepresentationConfigurable = serializer as IDictionaryRepresentationConfigurable;
if (dictionaryRepresentationConfigurable != null)
{
serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
}
var childSerializerConfigurable = serializer as IChildSerializerConfigurable;
return childSerializerConfigurable == null
? serializer
: childSerializerConfigurable.WithChildSerializer(ConfigureSerializer(childSerializerConfigurable.ChildSerializer));
}
}
다음과 같이 등록합니다.
ConventionRegistry.Register(
"DictionaryRepresentationConvention",
new ConventionPack {new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)},
_ => true);
위의 답변은 훌륭하지만 안타깝게도 StackOverflow를 트리거합니다.특정 재귀 개체 계층에 대한 예외 - 여기 약간 개선된 최신 버전이 있습니다.
public class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
{
private readonly DictionaryRepresentation _dictionaryRepresentation;
public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation = DictionaryRepresentation.ArrayOfDocuments)
{
// see http://mongodb.github.io/mongo-csharp-driver/2.2/reference/bson/mapping/#dictionary-serialization-options
_dictionaryRepresentation = dictionaryRepresentation;
}
public void Apply(BsonMemberMap memberMap)
{
memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer(),Array.Empty<IBsonSerializer>()));
}
private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer, IBsonSerializer[] stack)
{
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationConfigurable)
{
serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
}
if (serializer is IChildSerializerConfigurable childSerializerConfigurable)
{
if (!stack.Contains(childSerializerConfigurable.ChildSerializer))
{
var newStack = stack.Union(new[] { serializer }).ToArray();
var childConfigured = ConfigureSerializer(childSerializerConfigurable.ChildSerializer, newStack);
return childSerializerConfigurable.WithChildSerializer(childConfigured);
}
}
return serializer;
}
저처럼 클래스의 단일 필드에 이 기능을 적용하기를 원하신다면, 저는 이렇게 할 수 있었습니다(다른 답변 덕분에).
BsonClassMap.RegisterClassMap<TestClass>(cm =>
{
cm.AutoMap();
var memberMap = cm.GetMemberMap(x => x.DictionaryField);
var serializer = memberMap.GetSerializer();
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationSerializer)
serializer = dictionaryRepresentationSerializer.WithDictionaryRepresentation(DictionaryRepresentation.ArrayOfDocuments);
memberMap.SetSerializer(serializer);
});
또는 확장 방법으로:
BsonClassMap.RegisterClassMap<TestClass>(cm =>
{
cm.AutoMap();
cm.SetDictionaryRepresentation(x => x.DictionaryField, DictionaryRepresentation.ArrayOfDocuments);
});
public static class MapHelpers
{
public static BsonClassMap<T> SetDictionaryRepresentation<T, TMember>(this BsonClassMap<T> classMap, Expression<Func<T,TMember>> memberLambda, DictionaryRepresentation representation)
{
var memberMap = classMap.GetMemberMap(memberLambda);
var serializer = memberMap.GetSerializer();
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationSerializer)
serializer = dictionaryRepresentationSerializer.WithDictionaryRepresentation(representation);
memberMap.SetSerializer(serializer);
return classMap;
}
}
위의 코드로 시스템을 얻습니다.잘못된 작업예외: 'ValueFactory가 이 인스턴스의 Value 속성에 액세스하려고 시도했습니다.'
List<> 속성과 관련이 있습니다.
언급URL : https://stackoverflow.com/questions/28111846/bsonserializationexception-when-serializing-a-dictionarydatetime-t-to-bson
'programing' 카테고리의 다른 글
SQL Server Express(2012)와 LocalDB 사이에 차이점이 있습니까? (0) | 2023.06.25 |
---|---|
Vuejs 및 Vuex 작업 - 상태 코드 422로 요청 실패 (0) | 2023.06.25 |
유형 스크립트의 유형 오류 (0) | 2023.06.25 |
ORA-22905 - Select 문을 사용하여 테이블 유형을 쿼리할 수 있습니다. (0) | 2023.06.25 |
Mac OS X에 애드버타이즈 설정 (0) | 2023.06.25 |