Skip to content

Commit dca125f

Browse files
nurihrstam
authored andcommitted
CSHARP-2644: Add a convention for storing an _id declared as string in a POCO as ObjectId in the database.
1 parent 385bb3b commit dca125f

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using MongoDB.Bson.Serialization.IdGenerators;
2+
using MongoDB.Bson.Serialization.Serializers;
3+
4+
namespace MongoDB.Bson.Serialization.Conventions
5+
{
6+
/// <summary>
7+
/// A convention that sets representation of a string id class member to ObjectId in BSON with a StringObjectIdGenerator.
8+
/// </summary>
9+
public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConvention
10+
{
11+
/// <summary>
12+
/// Applies a post processing modification to the class map.
13+
/// </summary>
14+
/// <param name="memberMap">The BsonMemberMap map.</param>
15+
/// <remarks>This method sets both the serializer and the IdGenerator on the id member field.</remarks>
16+
public void Apply(BsonMemberMap memberMap)
17+
{
18+
var idMemberMap = memberMap.ClassMap?.IdMemberMap;
19+
20+
if (idMemberMap == null)
21+
{
22+
return;
23+
}
24+
25+
if (idMemberMap.MemberType != typeof(string))
26+
{
27+
return;
28+
}
29+
30+
if (idMemberMap.IdGenerator != null)
31+
{
32+
return;
33+
}
34+
35+
var idSerializer = idMemberMap.GetSerializer();
36+
37+
if (idSerializer is StringSerializer stringSerializer && stringSerializer.Representation == BsonType.String)
38+
{
39+
idMemberMap.SetSerializer(new StringSerializer(representation: BsonType.ObjectId));
40+
idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance);
41+
}
42+
}
43+
}
44+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using Xunit;
2+
using MongoDB.Bson.Serialization.Serializers;
3+
using MongoDB.Bson.Serialization;
4+
using MongoDB.Bson.Serialization.IdGenerators;
5+
using MongoDB.Bson.Serialization.Conventions;
6+
7+
namespace MongoDB.Bson.Tests.Serialization.Conventions
8+
{
9+
public class StringIdStoredAsObjectIdConventionTests
10+
{
11+
BsonMemberMap SampleMap<T>() => new BsonClassMap<T>(cm => cm.AutoMap()).GetMemberMap("Id");
12+
13+
[Fact]
14+
public void Apply_StringId_SetsSerializer()
15+
{
16+
var target = new StringIdStoredAsObjectIdConvention();
17+
var subject = SampleMap<TestClassWithStringId>();
18+
19+
target.Apply(subject);
20+
21+
Assert.IsType<StringSerializer>(subject.GetSerializer());
22+
}
23+
24+
[Fact]
25+
public void Apply_StringId_SetsIdGenerator()
26+
{
27+
var target = new StringIdStoredAsObjectIdConvention();
28+
var subject = SampleMap<TestClassWithStringId>();
29+
30+
target.Apply(subject);
31+
32+
Assert.IsType<StringObjectIdGenerator>(subject.IdGenerator);
33+
}
34+
35+
[Fact]
36+
public void Apply_ExistingIdGenerator_DoesNotApply()
37+
{
38+
var target = new StringIdStoredAsObjectIdConvention();
39+
var subject = SampleMap<TestClassWithStringId>();
40+
subject.SetIdGenerator(CombGuidGenerator.Instance);
41+
42+
target.Apply(subject);
43+
44+
Assert.IsType<CombGuidGenerator>(subject.IdGenerator);
45+
}
46+
47+
[Fact]
48+
public void Apply_NotStringSerializer_DoesNotApply()
49+
{
50+
var target = new StringIdStoredAsObjectIdConvention();
51+
var subject = SampleMap<TestClassWithStringId>();
52+
subject.SetSerializer(new FakeStringSerializer());
53+
54+
target.Apply(subject);
55+
56+
Assert.IsType<FakeStringSerializer>(subject.GetSerializer());
57+
}
58+
59+
60+
[Fact]
61+
public void Apply_IntId_LeavesSerializer()
62+
{
63+
var target = new StringIdStoredAsObjectIdConvention();
64+
var subject = SampleMap<TestClassWithIntId>();
65+
66+
target.Apply(subject);
67+
68+
Assert.IsNotType<StringSerializer>(subject.GetSerializer());
69+
}
70+
71+
[Fact]
72+
public void Apply_IntId_NoIdGenerator()
73+
{
74+
var target = new StringIdStoredAsObjectIdConvention();
75+
var subject = SampleMap<TestClassWithIntId>();
76+
77+
target.Apply(subject);
78+
79+
Assert.Null(subject.IdGenerator);
80+
}
81+
82+
83+
public class TestClassWithStringId { public string Id; }
84+
85+
public class TestClassWithIntId { public int Id; }
86+
87+
class FakeStringSerializer : SealedClassSerializerBase<string>
88+
{
89+
public BsonType Representation => BsonType.String;
90+
}
91+
}
92+
}
93+
94+
95+

0 commit comments

Comments
 (0)