diff --git a/README.md b/README.md
index e250795..2edf655 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ This [Dapper](https://github.com/SamSaffron/dapper-dot-net/) extension allows yo
### Usage
-Mapping properties:
-```
+#### Mapping properties using `EntityMap`
+```csharp
public class ProductMap : EntityMap
{
public ProductMap()
@@ -27,13 +27,54 @@ public class ProductMap : EntityMap
}
```
-Initializing Dapper.FluentMap:
-
-```
+Initialization:
+```csharp
FluentMapper.Intialize(config =>
{
- config.AddEntityMap(new ProductMap());
+ config.AddMap(new ProductMap());
});
```
-That's it. When querying the database using Dapper, the product name from column `strName` will be mapped to the `Name` property of the `Product` entity. `LastModifed` won't be mapped since we marked it as 'ignored'.
+#### Mapping properties using conventions
+
+You can create a convention by creating a class which derives from the `Convention` class. In the contructor you can configure the property conventions:
+```csharp
+public class TypePrefixConvention : Convention
+{
+ public TypePrefixConvention()
+ {
+ // Map all properties of type int and with the name 'id' to column 'autID'.
+ Properties()
+ .Where(c => c.Name.ToLower() == "id")
+ .Configure(c => c.HasColumnName("autID"));
+
+ // Prefix all properties of type string with 'str' when mapping to column names.
+ Properties()
+ .Configure(c => c.HasPrefix("str"));
+
+ // Prefix all properties of type int with 'int' when mapping to column names.
+ Properties()
+ .Configure(c => c.HasPrefix("int"));
+ }
+}
+```
+
+When initializing Dapper.FluentMap with conventions, the entities on which a convention applies must be configured. You can choose to either configure the entities explicitly or scan a specified, or the current assembly.
+
+```csharp
+FluentMapper.Intialize(config =>
+ {
+ // Configure entities explicitly.
+ config.AddConvention(new TypePrefixConvention())
+ .ForEntity()
+ .ForEntity;
+
+ // Configure all entities in a certain assembly with an optional namespaces filter.
+ config.AddConvention(new TypePrefixConvention())
+ .ForEntitiesInAssembly(typeof (Product).Assembly, "App.Domain.Model");
+
+ // Configure all entities in the current assembly with an optional namespaces filter.
+ config.AddConvention(new TypePrefixConvention())
+ .ForEntitiesInCurrentAssembly("App.Domain.Model.Catalog", "App.Domain.Model.Order");
+ });
+```
diff --git a/Dapper.FluentMap.1.0.0.nupkg b/nuget/Dapper.FluentMap.1.0.0.nupkg
similarity index 100%
rename from Dapper.FluentMap.1.0.0.nupkg
rename to nuget/Dapper.FluentMap.1.0.0.nupkg
diff --git a/Dapper.FluentMap.1.0.1.nupkg b/nuget/Dapper.FluentMap.1.0.1.nupkg
similarity index 100%
rename from Dapper.FluentMap.1.0.1.nupkg
rename to nuget/Dapper.FluentMap.1.0.1.nupkg
diff --git a/Dapper.FluentMap.1.0.2.nupkg b/nuget/Dapper.FluentMap.1.0.2.nupkg
similarity index 100%
rename from Dapper.FluentMap.1.0.2.nupkg
rename to nuget/Dapper.FluentMap.1.0.2.nupkg
diff --git a/nuget/Dapper.FluentMap.1.1.0.nupkg b/nuget/Dapper.FluentMap.1.1.0.nupkg
new file mode 100644
index 0000000..e5620f2
Binary files /dev/null and b/nuget/Dapper.FluentMap.1.1.0.nupkg differ
diff --git a/src/Dapper.FluentMap/Configuration/FluentConventionConfiguration.cs b/src/Dapper.FluentMap/Configuration/FluentConventionConfiguration.cs
new file mode 100644
index 0000000..434b2e7
--- /dev/null
+++ b/src/Dapper.FluentMap/Configuration/FluentConventionConfiguration.cs
@@ -0,0 +1,142 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using Dapper.FluentMap.Conventions;
+using Dapper.FluentMap.Mapping;
+using Dapper.FluentMap.Utils;
+
+namespace Dapper.FluentMap.Configuration
+{
+ ///
+ /// Defines methods for configuring conventions.
+ ///
+ public class FluentConventionConfiguration
+ {
+ private readonly Convention _convention;
+
+ ///
+ /// Initializes a new instance of the class,
+ /// allowing configuration of conventions.
+ ///
+ /// The convention.
+ public FluentConventionConfiguration(Convention convention)
+ {
+ _convention = convention;
+ }
+
+ ///
+ /// Configures the current covention for the specified entity type.
+ ///
+ /// The type of the entity.
+ /// The current instance of .
+ public FluentConventionConfiguration ForEntity()
+ {
+ Type type = typeof (T);
+ MapProperties(type);
+
+ FluentMapper.TypeConventions.AddOrUpdate(type, _convention);
+ FluentMapper.AddConventionTypeMap();
+ return this;
+ }
+
+ ///
+ /// Configures the current convention for all the entities in current assembly filtered by the specified namespaces.
+ ///
+ /// An array of namespaces which filter the types in the current assembly. This parameter is optional.
+ /// The current instance of .
+ public FluentConventionConfiguration ForEntitiesInCurrentAssembly(params string[] namespaces)
+ {
+ foreach (var type in Assembly.GetCallingAssembly()
+ .GetExportedTypes()
+ .Where(type => namespaces.Length == 0 || namespaces.Any(n => type.Namespace == n)))
+ {
+ MapProperties(type);
+ FluentMapper.TypeConventions.AddOrUpdate(type, _convention);
+ FluentMapper.AddConventionTypeMap(type);
+ }
+
+ return this;
+ }
+
+ ///
+ /// Configures the current convention for all entities in the specified assembly filtered by the specified namespaces.
+ ///
+ /// The assembly to scan for entities.
+ /// An array of namespaces which filter the types in . This parameter is optional.
+ /// The current instance of .
+ public FluentConventionConfiguration ForEntitiesInAssembly(Assembly assembly, params string[] namespaces)
+ {
+ foreach (var type in assembly.GetExportedTypes().Where(t => namespaces.Any(n => n.Contains(t.Namespace))))
+ {
+ MapProperties(type);
+ FluentMapper.TypeConventions.AddOrUpdate(type, _convention);
+ FluentMapper.AddConventionTypeMap(type);
+ }
+
+ return this;
+ }
+
+ private void MapProperties(Type type)
+ {
+ var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ foreach (var property in properties)
+ {
+ // Find the convention configurations for the convetion with either none or matching property predicates.
+ foreach (var config in _convention.ConventionConfigurations
+ .Where(c => c.PropertyPredicates.Count <= 0 ||
+ c.PropertyPredicates.All(e => e(property))))
+ {
+ if (!string.IsNullOrEmpty(config.Config.ColumnName))
+ {
+ AddConventionPropertyMap(property, config.Config.ColumnName);
+ break;
+ }
+
+ if (!string.IsNullOrEmpty(config.Config.Prefix))
+ {
+ AddConventionPropertyMap(property, config.Config.Prefix + property.Name);
+ break;
+ }
+ }
+ }
+ }
+
+ private void AddConventionPropertyMap(PropertyInfo property, string columnName)
+ {
+ var map = new PropertyMap(property, columnName);
+ _convention.PropertyMaps.Add(map);
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Configuration/FluentMapConfiguration.cs b/src/Dapper.FluentMap/Configuration/FluentMapConfiguration.cs
new file mode 100644
index 0000000..5f48013
--- /dev/null
+++ b/src/Dapper.FluentMap/Configuration/FluentMapConfiguration.cs
@@ -0,0 +1,67 @@
+using System;
+using System.ComponentModel;
+using Dapper.FluentMap.Conventions;
+using Dapper.FluentMap.Mapping;
+
+namespace Dapper.FluentMap.Configuration
+{
+ ///
+ /// Defines methods for configuring Dapper.FluentMap.
+ ///
+ public class FluentMapConfiguration
+ {
+ ///
+ /// Adds the specified to the configuration of Dapper.FluentMap.
+ ///
+ /// The type argument of the entity.
+ /// An instance of the EntityMap classs containing the entity mapping configuration.
+ public void AddMap(EntityMap mapper) where TEntity : class
+ {
+ FluentMapper.EntityMappers.Add(typeof (TEntity), mapper);
+ FluentMapper.AddTypeMap();
+ }
+
+ ///
+ /// Adds the specified to the configuration of Dapper.FluentMap.
+ ///
+ /// An instance of the class.
+ ///
+ /// An instance of
+ /// which allows configuration of the convention.
+ ///
+ public FluentConventionConfiguration AddConvention(Convention convention)
+ {
+ return new FluentConventionConfiguration(convention);
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Conventions/Convention.cs b/src/Dapper.FluentMap/Conventions/Convention.cs
new file mode 100644
index 0000000..2e2aa6a
--- /dev/null
+++ b/src/Dapper.FluentMap/Conventions/Convention.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Dapper.FluentMap.Mapping;
+
+namespace Dapper.FluentMap.Conventions
+{
+ ///
+ /// Represents a convention for mapping entity properties to column names.
+ ///
+ public abstract class Convention
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected Convention()
+ {
+ ConventionConfigurations = new List();
+ PropertyMaps = new List();
+ }
+
+ internal IList ConventionConfigurations { get; private set; }
+
+ internal IList PropertyMaps { get; private set; }
+
+ ///
+ /// Configures a convention that applies on all properties of the entity.
+ ///
+ /// A configuration object for the convention.
+ protected PropertyConventionConfiguration Properties()
+ {
+ var config = new PropertyConventionConfiguration();
+ ConventionConfigurations.Add(config);
+
+ return config;
+ }
+
+ ///
+ /// Configures a convention that applies on all the properties of a specified type of the entity.
+ ///
+ /// The type of the properties that the convention will apply to.
+ /// A configuration object for the convention.
+ protected PropertyConventionConfiguration Properties()
+ {
+ // Get the underlying type for a nullale type. (int? -> int)
+ Type underlyingType = Nullable.GetUnderlyingType(typeof (T)) ?? typeof (T);
+ var config = new PropertyConventionConfiguration().Where(p => p.PropertyType == underlyingType);
+ ConventionConfigurations.Add(config);
+
+ return config;
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Conventions/ConventionPropertyConfiguration.cs b/src/Dapper.FluentMap/Conventions/ConventionPropertyConfiguration.cs
new file mode 100644
index 0000000..032b6dc
--- /dev/null
+++ b/src/Dapper.FluentMap/Conventions/ConventionPropertyConfiguration.cs
@@ -0,0 +1,67 @@
+using System;
+using System.ComponentModel;
+
+namespace Dapper.FluentMap.Conventions
+{
+ ///
+ /// Represents configuration of a property via conventions.
+ ///
+ public class ConventionPropertyConfiguration
+ {
+ internal string ColumnName { get; private set; }
+
+ internal string Prefix { get; private set; }
+
+ ///
+ /// Configures the name of the database column used to store the property.
+ ///
+ /// The name of the database column.
+ /// The same instance of .
+ public ConventionPropertyConfiguration HasColumnName(string columnName)
+ {
+ ColumnName = columnName;
+ return this;
+ }
+
+ ///
+ /// Configures the prefix of the database column used to store the property.
+ ///
+ /// The prefix of the database column.
+ /// The same instance of .
+ public ConventionPropertyConfiguration HasPrefix(string prefix)
+ {
+ Prefix = prefix;
+ return this;
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Conventions/PropertyConventionConfiguration.cs b/src/Dapper.FluentMap/Conventions/PropertyConventionConfiguration.cs
new file mode 100644
index 0000000..08da724
--- /dev/null
+++ b/src/Dapper.FluentMap/Conventions/PropertyConventionConfiguration.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace Dapper.FluentMap.Conventions
+{
+ ///
+ /// Represents the configuration for a convention.
+ ///
+ public class PropertyConventionConfiguration
+ {
+ ///
+ /// Initializes a new instance of the class,
+ /// allowing configuration for a convention.
+ ///
+ public PropertyConventionConfiguration()
+ {
+ PropertyPredicates = new List>();
+ }
+
+ internal IList> PropertyPredicates { get; private set; }
+
+ internal ConventionPropertyConfiguration Config { get; private set; }
+
+ ///
+ /// Filters the properties that this convention applies to based on a predicate.
+ ///
+ /// A function to test each property for a condition.
+ /// The same instance of .
+ public PropertyConventionConfiguration Where(Func predicate)
+ {
+ PropertyPredicates.Add(predicate);
+ return this;
+ }
+
+ ///
+ /// Configures the properties that this convention applies to.
+ ///
+ /// An action that performs configuration against .
+ public void Configure(Action configure)
+ {
+ var config = new ConventionPropertyConfiguration();
+ Config = config;
+ configure(config);
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Dapper.FluentMap.csproj b/src/Dapper.FluentMap/Dapper.FluentMap.csproj
index 63060ac..af74e48 100644
--- a/src/Dapper.FluentMap/Dapper.FluentMap.csproj
+++ b/src/Dapper.FluentMap/Dapper.FluentMap.csproj
@@ -45,14 +45,20 @@
-
-
+
+
+
+
+
+
-
-
+
+
+
-
-
+
+
+
diff --git a/src/Dapper.FluentMap/FluentMapConfiguration.cs b/src/Dapper.FluentMap/FluentMapConfiguration.cs
deleted file mode 100644
index 704a102..0000000
--- a/src/Dapper.FluentMap/FluentMapConfiguration.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace Dapper.FluentMap
-{
- ///
- /// Defines methods for configuring Dapper.FluentMap.
- ///
- public interface IFluentMapConfiguration
- {
- ///
- /// Adds the specified EntityMap to the configuration of Dapper.FluentMap.
- ///
- /// The type argument of the entity.
- /// An instance of the EntityMap classs containing the entity mapping configuration.
- void AddEntityMap(EntityMap mapper) where TEntity : class;
- }
-
- public class FluentMapConfiguration : IFluentMapConfiguration
- {
- public void AddEntityMap(EntityMap mapper) where TEntity : class
- {
- FluentMapper.EntityMappers.Add(typeof (TEntity), mapper);
- FluentMapper.AddTypeMap();
- }
- }
-}
diff --git a/src/Dapper.FluentMap/FluentMapper.cs b/src/Dapper.FluentMap/FluentMapper.cs
index 358f648..16af4b9 100644
--- a/src/Dapper.FluentMap/FluentMapper.cs
+++ b/src/Dapper.FluentMap/FluentMapper.cs
@@ -1,5 +1,9 @@
using System;
using System.Collections.Generic;
+using Dapper.FluentMap.Configuration;
+using Dapper.FluentMap.Conventions;
+using Dapper.FluentMap.Mapping;
+using Dapper.FluentMap.TypeMaps;
namespace Dapper.FluentMap
{
@@ -8,25 +12,30 @@ namespace Dapper.FluentMap
///
public static class FluentMapper
{
- private static readonly IFluentMapConfiguration _configuration = new FluentMapConfiguration();
+ private static readonly FluentMapConfiguration _configuration = new FluentMapConfiguration();
///
/// Gets the dictionary containing the entity mapping per entity type.
///
internal static readonly IDictionary EntityMappers = new Dictionary();
+ ///
+ /// Gets the dictionairy containing the conventions per entity type.
+ ///
+ internal static readonly IDictionary> TypeConventions = new Dictionary>();
+
///
/// Initializes Dapper.FluentMap with the specified configuration.
/// This is method should be called when the application starts or when the first mapping is needed.
///
/// A callback containing the configuration of Dapper.FluentMap.
- public static void Intialize(Action configure)
+ public static void Intialize(Action configure)
{
configure(_configuration);
}
///
- /// Registers a Dapper type map for the specified .
+ /// Registers a Dapper type map using fluent mapping for the specified .
///
/// The type of the entity.
internal static void AddTypeMap()
@@ -35,7 +44,7 @@ internal static void AddTypeMap()
}
///
- /// Registers a Dapper type map for the specified .
+ /// Registers a Dapper type map using fluent mapping for the specified .
///
/// The type of the entity.
internal static void AddTypeMap(Type entityType)
@@ -43,5 +52,24 @@ internal static void AddTypeMap(Type entityType)
var instance = (SqlMapper.ITypeMap)Activator.CreateInstance(typeof (FluentMapTypeMap<>).MakeGenericType(entityType));
SqlMapper.SetTypeMap(entityType, instance);
}
+
+ ///
+ /// Registers a Dapper type map using conventions for the specified .
+ ///
+ /// The type of the entity.
+ internal static void AddConventionTypeMap()
+ {
+ SqlMapper.SetTypeMap(typeof (TEntity), new FluentConventionTypeMap());
+ }
+
+ ///
+ /// Registers a Dapper type map using conventions for the specified .
+ ///
+ /// The type of the entity.
+ internal static void AddConventionTypeMap(Type entityType)
+ {
+ var instance = (SqlMapper.ITypeMap)Activator.CreateInstance(typeof (FluentConventionTypeMap<>).MakeGenericType(entityType));
+ SqlMapper.SetTypeMap(entityType, instance);
+ }
}
}
diff --git a/src/Dapper.FluentMap/EntityMap.cs b/src/Dapper.FluentMap/Mapping/EntityMap.cs
similarity index 96%
rename from src/Dapper.FluentMap/EntityMap.cs
rename to src/Dapper.FluentMap/Mapping/EntityMap.cs
index 22940ff..ac4e5af 100644
--- a/src/Dapper.FluentMap/EntityMap.cs
+++ b/src/Dapper.FluentMap/Mapping/EntityMap.cs
@@ -2,8 +2,9 @@
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
+using Dapper.FluentMap.Utils;
-namespace Dapper.FluentMap
+namespace Dapper.FluentMap.Mapping
{
///
/// Represents a non-typed mapping of an entity.
diff --git a/src/Dapper.FluentMap/Mapping/PropertyMap.cs b/src/Dapper.FluentMap/Mapping/PropertyMap.cs
new file mode 100644
index 0000000..43bc3c5
--- /dev/null
+++ b/src/Dapper.FluentMap/Mapping/PropertyMap.cs
@@ -0,0 +1,102 @@
+using System;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace Dapper.FluentMap.Mapping
+{
+ ///
+ /// Represents the mapping of a property.
+ ///
+ public class PropertyMap
+ {
+ ///
+ /// Initializes a new instance of the using
+ /// the specified object representing the property to map.
+ ///
+ /// The object representing to the property to map.
+ internal PropertyMap(PropertyInfo info)
+ {
+ PropertyInfo = info;
+ ColumnName = info.Name;
+ }
+
+ ///
+ /// Initializes a new instance of the using
+ /// the specified object representing the property to map
+ /// and column name to map the property to.
+ ///
+ /// The object representing to the property to map.
+ /// The column name in the database to map the property to.
+ internal PropertyMap(PropertyInfo info, string columnName)
+ {
+ PropertyInfo = info;
+ ColumnName = columnName;
+ }
+
+ ///
+ /// Gets the name of the column in the data store.
+ ///
+ internal string ColumnName { get; private set; }
+
+ ///
+ /// Gets a value indicating wether the property should be ignored when mapping.
+ ///
+ internal bool Ignored { get; private set; }
+
+ ///
+ /// Gets the object for the current property.
+ ///
+ internal PropertyInfo PropertyInfo { get; private set; }
+
+ ///
+ /// Maps the current property to the specified column name.
+ ///
+ /// The name of the column in the data store.
+ /// The current instance. This enables a fluent API.
+ public PropertyMap ToColumn(string columnName)
+ {
+ ColumnName = columnName;
+ return this;
+ }
+
+ ///
+ /// Marks the current property as ignored, resulting in the property not being mapped by Dapper.
+ ///
+ /// The current instance. This enables a fluent API.
+ public PropertyMap Ignore()
+ {
+ Ignored = true;
+ return this;
+ }
+
+ #region EditorBrowsableStates
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString()
+ {
+ return base.ToString();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new Type GetType()
+ {
+ return base.GetType();
+ }
+ #endregion
+ }
+}
diff --git a/src/Dapper.FluentMap/Properties/AssemblyInfo.cs b/src/Dapper.FluentMap/Properties/AssemblyInfo.cs
index a511002..0422143 100644
--- a/src/Dapper.FluentMap/Properties/AssemblyInfo.cs
+++ b/src/Dapper.FluentMap/Properties/AssemblyInfo.cs
@@ -32,5 +32,4 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.2.0")]
-[assembly: AssemblyFileVersion("1.0.2.0")]
+[assembly: AssemblyVersion("1.1.0")]
diff --git a/src/Dapper.FluentMap/PropertyMap.cs b/src/Dapper.FluentMap/PropertyMap.cs
deleted file mode 100644
index 883bffd..0000000
--- a/src/Dapper.FluentMap/PropertyMap.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Reflection;
-
-namespace Dapper.FluentMap
-{
- public class PropertyMap
- {
- ///
- /// Initializes a new instance of the using
- /// the specified object representing the property to map.
- ///
- ///
- public PropertyMap(PropertyInfo info)
- {
- PropertyInfo = info;
- ColumnName = info.Name;
- }
-
- ///
- /// Gets the name of the column in the data store.
- ///
- internal string ColumnName { get; private set; }
-
- ///
- /// Gets a value indicating wether the property should be ignored when mapping.
- ///
- internal bool Ignored { get; private set; }
-
- ///
- /// Gets the object for the current property.
- ///
- internal PropertyInfo PropertyInfo { get; private set; }
-
- ///
- /// Maps the current property to the specified column name.
- ///
- /// The name of the column in the data store.
- /// The current instance. This enables a fluent API.
- public PropertyMap ToColumn(string columnName)
- {
- ColumnName = columnName;
- return this;
- }
-
- ///
- /// Marks the current property as ignored, resulting in the property not being mapped by Dapper.
- ///
- /// The current instance. This enables a fluent API.
- public PropertyMap Ignore()
- {
- Ignored = true;
- return this;
- }
- }
-}
diff --git a/src/Dapper.FluentMap/TypeMaps/FluentConventionTypeMap.cs b/src/Dapper.FluentMap/TypeMaps/FluentConventionTypeMap.cs
new file mode 100644
index 0000000..073e27a
--- /dev/null
+++ b/src/Dapper.FluentMap/TypeMaps/FluentConventionTypeMap.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Dapper.FluentMap.Conventions;
+
+namespace Dapper.FluentMap.TypeMaps
+{
+ ///
+ /// Represents a Dapper type mapping strategy which first tries to map the type using a
+ /// with the configured conventions. is used as fallback mapping strategy.
+ ///
+ /// The type of the entity.
+ internal class FluentConventionTypeMap : MultiTypeMap
+ {
+ ///
+ /// Intializes a new instance of the class
+ /// which uses the and
+ /// as mapping strategies.
+ ///
+ public FluentConventionTypeMap()
+ : base(new CustomPropertyTypeMap(typeof (TEntity), GetPropertyInfo), new DefaultTypeMap(typeof (TEntity)))
+ {
+ }
+
+ private static PropertyInfo GetPropertyInfo(Type type, string columnName)
+ {
+ string cacheKey = string.Format("{0};{1}", type.FullName, columnName);
+
+ PropertyInfo info;
+ if (TypePropertyMapCache.TryGetValue(cacheKey, out info))
+ {
+ return info;
+ }
+
+ IList conventions;
+ if (FluentMapper.TypeConventions.TryGetValue(type, out conventions))
+ {
+ foreach (var convention in conventions)
+ {
+ var maps = convention.PropertyMaps.Where(c => c.ColumnName == columnName).ToList();
+
+ if (maps.Count > 1)
+ {
+ const string msg = "Finding mappings for column '{0}' yielded more than 1 PropertyMap. The conventions should be more specific. Type: '{1}'. Convention: '{2}'.";
+ throw new Exception(string.Format(msg, columnName, type, convention));
+ }
+
+ if (maps.Count == 0)
+ {
+ return null;
+ }
+
+ info = maps[0].PropertyInfo;
+ TypePropertyMapCache.Add(cacheKey, info);
+ return info;
+ }
+ }
+
+ // If we get here, the property was not mapped.
+ TypePropertyMapCache.Add(cacheKey, null);
+ return null;
+ }
+ }
+}
diff --git a/src/Dapper.FluentMap/FluentMapTypeMap.cs b/src/Dapper.FluentMap/TypeMaps/FluentTypeMap.cs
similarity index 84%
rename from src/Dapper.FluentMap/FluentMapTypeMap.cs
rename to src/Dapper.FluentMap/TypeMaps/FluentTypeMap.cs
index 223b8d0..5623710 100644
--- a/src/Dapper.FluentMap/FluentMapTypeMap.cs
+++ b/src/Dapper.FluentMap/TypeMaps/FluentTypeMap.cs
@@ -1,15 +1,16 @@
using System;
using System.Linq;
using System.Reflection;
+using Dapper.FluentMap.Mapping;
-namespace Dapper.FluentMap
+namespace Dapper.FluentMap.TypeMaps
{
///
/// Represents a Dapper type mapping strategy which first tries to map the type using a ,
/// if that fails, the is used as mapping strategy.
///
/// The type of the entity.
- public class FluentMapTypeMap : MultiTypeMap
+ internal class FluentMapTypeMap : MultiTypeMap
{
///
/// Intializes a new instance of the class
@@ -26,7 +27,7 @@ private static PropertyInfo GetPropertyInfo(Type type, string columnName)
string cacheKey = string.Format("{0};{1}", type.FullName, columnName);
PropertyInfo info;
- if (_typePropertyMapCache.TryGetValue(cacheKey, out info))
+ if (TypePropertyMapCache.TryGetValue(cacheKey, out info))
{
return info;
}
@@ -43,14 +44,14 @@ private static PropertyInfo GetPropertyInfo(Type type, string columnName)
{
if (!propertyMap.Ignored)
{
- _typePropertyMapCache.Add(cacheKey, propertyMap.PropertyInfo);
+ TypePropertyMapCache.Add(cacheKey, propertyMap.PropertyInfo);
return propertyMap.PropertyInfo;
}
}
}
// If we get here, the property was not mapped.
- _typePropertyMapCache.Add(cacheKey, null);
+ TypePropertyMapCache.Add(cacheKey, null);
return null;
}
}
diff --git a/src/Dapper.FluentMap/MultiTypeMap.cs b/src/Dapper.FluentMap/TypeMaps/MultiTypeMap.cs
similarity index 82%
rename from src/Dapper.FluentMap/MultiTypeMap.cs
rename to src/Dapper.FluentMap/TypeMaps/MultiTypeMap.cs
index bc589ef..424e1df 100644
--- a/src/Dapper.FluentMap/MultiTypeMap.cs
+++ b/src/Dapper.FluentMap/TypeMaps/MultiTypeMap.cs
@@ -2,18 +2,19 @@
using System.Collections.Generic;
using System.Reflection;
-namespace Dapper.FluentMap
+namespace Dapper.FluentMap.TypeMaps
{
///
/// Represents a Dapper type mapping strategy which consists of multiple strategies.
///
- public abstract class MultiTypeMap : SqlMapper.ITypeMap
+ internal abstract class MultiTypeMap : SqlMapper.ITypeMap
{
- protected static readonly Dictionary _typePropertyMapCache = new Dictionary();
private readonly IEnumerable _mappers;
+ private static readonly Dictionary _typePropertyMapCache = new Dictionary();
///
- /// Initializes an instance of the class with the specified Dapper type mappers.
+ /// Initializes an instance of the
+ /// class with the specified Dapper type mappers.
///
/// The type mapping strategies to be used when mapping.
protected MultiTypeMap(params SqlMapper.ITypeMap[] mappers)
@@ -88,5 +89,13 @@ public SqlMapper.IMemberMap GetMember(string columnName)
}
return null;
}
+
+ protected static Dictionary TypePropertyMapCache
+ {
+ get
+ {
+ return _typePropertyMapCache;
+ }
+ }
}
}
diff --git a/src/Dapper.FluentMap/Utils/DictionaryExtensions.cs b/src/Dapper.FluentMap/Utils/DictionaryExtensions.cs
new file mode 100644
index 0000000..37086f4
--- /dev/null
+++ b/src/Dapper.FluentMap/Utils/DictionaryExtensions.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace Dapper.FluentMap.Utils
+{
+ internal static class DictionaryExtensions
+ {
+ internal static void AddOrUpdate(this IDictionary> dict, TKey key, TValue value)
+ {
+ if (dict.ContainsKey(key))
+ {
+ dict[key].Add(value);
+ }
+ else
+ {
+ dict.Add(key, new[] { value });
+ }
+ }
+ }
+}
diff --git a/src/Dapper.FluentMap/ReflectionHelper.cs b/src/Dapper.FluentMap/Utils/ReflectionHelper.cs
similarity index 82%
rename from src/Dapper.FluentMap/ReflectionHelper.cs
rename to src/Dapper.FluentMap/Utils/ReflectionHelper.cs
index e24d796..e627519 100644
--- a/src/Dapper.FluentMap/ReflectionHelper.cs
+++ b/src/Dapper.FluentMap/Utils/ReflectionHelper.cs
@@ -1,19 +1,19 @@
using System.Linq.Expressions;
using System.Reflection;
-namespace Dapper.FluentMap
+namespace Dapper.FluentMap.Utils
{
///
/// Provides helper methods for reflection operations.
///
- public static class ReflectionHelper
+ internal static class ReflectionHelper
{
///
- /// Returns the MemberInfo for the specified lamba expression.
+ /// Returns the for the specified lamba expression.
///
/// A lamba expression containing a MemberExpression.
/// A MemberInfo object for the member in the specified lambda expression.
- public static MemberInfo GetMemberInfo(LambdaExpression lambda)
+ internal static MemberInfo GetMemberInfo(LambdaExpression lambda)
{
Expression expr = lambda;
while (true)