Permalink
Browse files

Added support for Id's defined in interfaces by the MongoIdentifierAt…

…tribute.
  • Loading branch information...
1 parent 48433fc commit 715fdf8330d80215a2f8ddaee8ee0eaf3ba12593 @ereichert ereichert committed Apr 25, 2010
Showing with 76 additions and 20 deletions.
  1. +6 −0 NoRM.Tests/IdPropertyFinderTests.cs
  2. +3 −2 NoRM.Tests/TypeHelperTests.cs
  3. +48 −18 NoRM/BSON/IdPropertyFinder.cs
  4. +19 −0 NoRM/BSON/TypeHelper.cs
View
6 NoRM.Tests/IdPropertyFinderTests.cs
@@ -63,6 +63,12 @@ public void FindIdProperty_Returns_Null_When_Entity_Has_No_Id_Defined()
{
Assert.Null(new IdPropertyFinder(typeof(EntityWithNoId)).IdProperty);
}
+
+ [Fact]
+ public void FindIdPropert_Returns_Id_Specified_By_Attribute_In_Implemented_Interface()
+ {
+ Assert.Equal("MyId", new IdPropertyFinder(typeof(DtoWithNonDefaultIdClass)).IdProperty.Name);
+ }
}
public class EntityWithNoId
View
5 NoRM.Tests/TypeHelperTests.cs
@@ -37,12 +37,13 @@ public void Can_Get_Id_Property_For_Type()
Assert.NotNull(helper.FindIdProperty());
}
- [Fact(Skip = "Karl doesn't think this is possible")]
+ [Fact]
public void Can_Infer_ID_From_Interface_Attribute()
{
var helper = TypeHelper.GetHelperForType(typeof(DtoWithNonDefaultIdClass));
+ var something = helper.FindIdProperty();
- Assert.NotNull(helper.FindIdProperty());
+ Assert.NotNull(something);
}
}
}
View
66 NoRM/BSON/IdPropertyFinder.cs
@@ -10,18 +10,19 @@ namespace Norm.BSON
/// Determines the best property to be used as the identifier property.
///</summary>
public class IdPropertyFinder
- {
+ {
private readonly Dictionary<IdType, PropertyInfo> _idDictionary;
private readonly Type _type;
private PropertyInfo[] _properties;
+ private PropertyInfo[] _interfaceProperties;
///<summary>
/// Initializes new IdPropertyFinder.
///</summary>
///<param name="type">The type for which an id property needs to be identified.</param>
public IdPropertyFinder(Type type)
{
- _type = type;
+ _type = type;
_idDictionary = new Dictionary<IdType, PropertyInfo>(4)
{
{ IdType.MongoDefault, null },
@@ -64,15 +65,15 @@ public PropertyInfo IdProperty
/// <summary>
/// Determines if the Id has been explicitly defined in a MongoConfigurationMap <see cref="MongoConfigurationMap"/>.
/// </summary>
- /// <param name="propertyName">The property name.</param>
- private bool PropertyIsExplicitlyMappedToId(string propertyName)
+ /// <param name="idPropertyCandidate">The property name.</param>
+ private bool PropertyIsExplicitlyMappedToId(string idPropertyCandidate)
{
var map = MongoTypeConfiguration.PropertyMaps;
if (map.ContainsKey(_type))
{
- if (map[_type].ContainsKey(propertyName))
+ if (map[_type].ContainsKey(idPropertyCandidate))
{
- return map[_type][propertyName].IsId;
+ return map[_type][idPropertyCandidate].IsId;
}
}
return false;
@@ -81,32 +82,59 @@ private bool PropertyIsExplicitlyMappedToId(string propertyName)
private void CheckForConflictingCandidates()
{
//This could be written as one line (MongoDefault && (MapDefined || AttributeDefined)) but two lines is more clearer.
- //This has the potential to become cumbersome should we discover more conflicts.
+ //This has the potential to become cumbersome should we discover more conflicts.
if (_idDictionary[IdType.MongoDefault] != null)
- {
+ {
if (_idDictionary[IdType.MapDefined] != null || _idDictionary[IdType.AttributeDefined] != null)
{
throw new MongoConfigurationMapException(_type.Name + " exposes a property called _id and defines a an Id using MongoIndentifier or by explicit mapping.");
}
}
}
+ private static bool HasMongoIdentifierAttribute(ICustomAttributeProvider idPropertyCandidate)
+ {
+ return idPropertyCandidate.GetCustomAttributes(BsonHelper.MongoIdentifierAttribute, true).Length > 0;
+ }
+
+ private bool PropertyIsAttributeDefinedId(MemberInfo idPropertyCandidate)
+ {
+ if (HasMongoIdentifierAttribute(idPropertyCandidate))
+ {
+ return true;
+ }
+
+ if (_interfaceProperties != null)
+ {
+ var interfacePropertiesWithSameNameAsCandidate = _interfaceProperties.Where(propertyInfo => propertyInfo.Name == idPropertyCandidate.Name);
+ foreach (PropertyInfo nextProperty in interfacePropertiesWithSameNameAsCandidate)
+ {
+ if (HasMongoIdentifierAttribute(nextProperty))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
private void AddCandidate(PropertyInfo property)
{
if (PropertyIsExplicitlyMappedToId(property.Name))
- {
+ {
_idDictionary[IdType.MapDefined] = property;
}
- else if (property.GetCustomAttributes(BsonHelper.MongoIdentifierAttribute, true).Length > 0)
- {
+ else if (PropertyIsAttributeDefinedId(property))
+ {
_idDictionary[IdType.AttributeDefined] = property;
}
else if (property.Name.Equals("_id", StringComparison.InvariantCultureIgnoreCase))
- {
+ {
_idDictionary[IdType.MongoDefault] = property;
}
else if (property.Name.Equals("Id", StringComparison.InvariantCultureIgnoreCase))
- {
+ {
_idDictionary[IdType.Conventional] = property;
}
}
@@ -118,18 +146,20 @@ private void AddCandidates()
_properties = TypeHelper.GetProperties(_type);
}
+ _interfaceProperties = TypeHelper.GetInterfaceProperties(_type);
+
foreach (var property in _properties)
{
AddCandidate(property);
}
}
private enum IdType
- {
- MapDefined,
- AttributeDefined,
- MongoDefault,
- Conventional,
+ {
+ MapDefined,
+ AttributeDefined,
+ MongoDefault,
+ Conventional,
}
}
View
19 NoRM/BSON/TypeHelper.cs
@@ -45,6 +45,25 @@ public static PropertyInfo[] GetProperties(Type type)
BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
}
+ public static PropertyInfo[] GetInterfaceProperties(Type type)
+ {
+ List<PropertyInfo> interfaceProperties;
+ Type[] interfaces = type.GetInterfaces();
+
+ if (interfaces.Count() != 0)
+ {
+ interfaceProperties = new List<PropertyInfo>();
+ foreach (Type nextInterface in interfaces)
+ {
+ PropertyInfo[] intProps = GetProperties(nextInterface);
+ interfaceProperties.AddRange(intProps);
+ }
+ return interfaceProperties.ToArray();
+ }
+
+ return null;
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="TypeHelper"/> class.
/// </summary>

0 comments on commit 715fdf8

Please sign in to comment.