From 16494cf79e5e2a826b0249b7e01a315293d7650c Mon Sep 17 00:00:00 2001 From: craiggwilson Date: Sun, 24 Oct 2010 01:09:26 -0500 Subject: [PATCH] added IdPropertyConvention --- Bson/Bson.csproj | 1 + Bson/DefaultSerializer/BsonClassMap.cs | 19 ++----- .../Conventions/ConventionProfile.cs | 32 ++++++++--- .../Conventions/IdPropertyConventions.cs | 28 ++++++++++ BsonUnitTests/BsonUnitTests.csproj | 1 + .../DefaultSerializer/BsonClassMapTests.cs | 2 +- .../Conventions/IdPropertyConventionsTests.cs | 54 +++++++++++++++++++ 7 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 Bson/DefaultSerializer/Conventions/IdPropertyConventions.cs create mode 100644 BsonUnitTests/DefaultSerializer/Conventions/IdPropertyConventionsTests.cs diff --git a/Bson/Bson.csproj b/Bson/Bson.csproj index f1599b30b4..a02fd1d3d8 100644 --- a/Bson/Bson.csproj +++ b/Bson/Bson.csproj @@ -76,6 +76,7 @@ + diff --git a/Bson/DefaultSerializer/BsonClassMap.cs b/Bson/DefaultSerializer/BsonClassMap.cs index 285c437dd5..d693c6fd3c 100644 --- a/Bson/DefaultSerializer/BsonClassMap.cs +++ b/Bson/DefaultSerializer/BsonClassMap.cs @@ -38,7 +38,8 @@ namespace MongoDB.Bson.DefaultSerializer { #region protected fields protected bool baseClassMapLoaded; // lazy load baseClassMap so class maps can be constructed out of order protected BsonClassMap baseClassMap; // null for class object and interfaces - protected Type classType; + protected Type classType; + protected ConventionProfile conventions; protected string discriminator; protected bool discriminatorIsRequired; protected bool isAnonymous; @@ -53,7 +54,8 @@ namespace MongoDB.Bson.DefaultSerializer { protected BsonClassMap( Type classType ) { - this.classType = classType; + this.classType = classType; + this.conventions = GetConventionProfile(this.classType); this.discriminator = classType.Name; this.isAnonymous = IsAnonymousType(classType); } @@ -271,8 +273,6 @@ namespace MongoDB.Bson.DefaultSerializer { BsonClassMap.LookupClassMap(knownTypeAttribute.KnownType); // will AutoMap KnownType if necessary } - var conventions = GetConventionProfile(classType); - var discriminatorAttribute = (BsonDiscriminatorAttribute) classType.GetCustomAttributes(typeof(BsonDiscriminatorAttribute), false).FirstOrDefault(); if (discriminatorAttribute != null) { discriminator = discriminatorAttribute.Discriminator; @@ -453,16 +453,7 @@ namespace MongoDB.Bson.DefaultSerializer { // if no base class provided an idPropertyMap maybe we have one? if (idPropertyMap == null) { - // TODO: improve Id detection algorithm (doesn't have to be perfect since BsonIdAttribute can always pinpoint the Id property) - // simple algorithm: first property found that ends in either "Id" or "id" or is of type ObjectId or Guid - idPropertyMap = propertyMaps - .Where(pm => - pm.PropertyName.EndsWith("Id") || - pm.PropertyName.EndsWith("id") || - pm.PropertyType == typeof(ObjectId) || - pm.PropertyType == typeof(Guid) - ) - .FirstOrDefault(); + idPropertyMap = conventions.IdPropertyConvention.FindIdPropertyMap(propertyMaps); } } diff --git a/Bson/DefaultSerializer/Conventions/ConventionProfile.cs b/Bson/DefaultSerializer/Conventions/ConventionProfile.cs index 28e5abde8c..c026e1bd25 100644 --- a/Bson/DefaultSerializer/Conventions/ConventionProfile.cs +++ b/Bson/DefaultSerializer/Conventions/ConventionProfile.cs @@ -6,20 +6,38 @@ using System.Text; namespace MongoDB.Bson.DefaultSerializer.Conventions { public sealed class ConventionProfile { - public static ConventionProfile Default { get; set; } + public static ConventionProfile Default { get; private set; } public IElementNameConvention ElementNameConvention { get; private set; } - static ConventionProfile() - { - Default = new ConventionProfile() - .SetElementNameConvention(new MemberNameElementNameConvention()); + public IIdPropertyConvention IdPropertyConvention { get; private set; } + + public Func TypeFilter { get; private set; } + + static ConventionProfile() { + Default = new ConventionProfile(t => true) //The default profile always matches... + .SetElementNameConvention(new MemberNameElementNameConvention()) + .SetIdPropertyConvention(new NamedIdPropertyConvention("Id")); + } + + public ConventionProfile( + Func typeFilter + ) { + TypeFilter = typeFilter; } - public ConventionProfile SetElementNameConvention(IElementNameConvention convention) - { + public ConventionProfile SetElementNameConvention( + IElementNameConvention convention + ) { ElementNameConvention = convention; return this; } + + public ConventionProfile SetIdPropertyConvention( + IIdPropertyConvention convention + ) { + IdPropertyConvention = convention; + return this; + } } } \ No newline at end of file diff --git a/Bson/DefaultSerializer/Conventions/IdPropertyConventions.cs b/Bson/DefaultSerializer/Conventions/IdPropertyConventions.cs new file mode 100644 index 0000000000..9eedf5033f --- /dev/null +++ b/Bson/DefaultSerializer/Conventions/IdPropertyConventions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; + +namespace MongoDB.Bson.DefaultSerializer.Conventions +{ + public interface IIdPropertyConvention { + BsonPropertyMap FindIdPropertyMap(IEnumerable propertyMaps); + } + + public class NamedIdPropertyConvention : IIdPropertyConvention { + public string Name { get; private set; } + + public NamedIdPropertyConvention( + string name + ) { + Name = name; + } + + public BsonPropertyMap FindIdPropertyMap( + IEnumerable propertyMaps + ) { + return propertyMaps.FirstOrDefault(x => x.PropertyName == Name); + } + } +} \ No newline at end of file diff --git a/BsonUnitTests/BsonUnitTests.csproj b/BsonUnitTests/BsonUnitTests.csproj index a762cb7e54..fd7551abd1 100644 --- a/BsonUnitTests/BsonUnitTests.csproj +++ b/BsonUnitTests/BsonUnitTests.csproj @@ -74,6 +74,7 @@ + diff --git a/BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs b/BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs index 8a45aa728d..a93959ed2c 100644 --- a/BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs +++ b/BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs @@ -37,7 +37,7 @@ namespace MongoDB.BsonUnitTests.DefaultSerializer { } [Test] - public void TestInt16UseCompactRepresentation() { + public void TestInt16UseCompactRepresentation() { var classMap = BsonClassMap.RegisterClassMap(); var sdPropertyMap = classMap.GetPropertyMap("SD"); var sfPropertyMap = classMap.GetPropertyMap("SF"); diff --git a/BsonUnitTests/DefaultSerializer/Conventions/IdPropertyConventionsTests.cs b/BsonUnitTests/DefaultSerializer/Conventions/IdPropertyConventionsTests.cs new file mode 100644 index 0000000000..3a67eda1ea --- /dev/null +++ b/BsonUnitTests/DefaultSerializer/Conventions/IdPropertyConventionsTests.cs @@ -0,0 +1,54 @@ +/* Copyright 2010 10gen Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using NUnit.Framework; + +using MongoDB.Bson.DefaultSerializer.Conventions; +using MongoDB.Bson; +using MongoDB.Bson.DefaultSerializer; + +namespace MongoDB.BsonUnitTests.DefaultSerializer.Conventions +{ + [TestFixture] + public class IdPropertyConventionsTests { + private class TestClassA { + public Guid Id { get; set; } + public ObjectId OtherId { get; set; } + } + + private class TestClassB { + public ObjectId OtherId { get; set; } + } + + [Test] + public void TestIdPropertyConvention() { + var convention = new NamedIdPropertyConvention("Id"); + + var classAMap = BsonClassMap.RegisterClassMap(); + var idMap = convention.FindIdPropertyMap(classAMap.PropertyMaps); + Assert.IsNotNull(idMap); + Assert.AreEqual("Id", idMap.PropertyName); + + var classBMap = BsonClassMap.RegisterClassMap(); + idMap = convention.FindIdPropertyMap(classBMap.PropertyMaps); + Assert.IsNull(idMap); + } + } +}