Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
Merge pull request #2 from HenkMollema/conventions
Browse files Browse the repository at this point in the history
Merge branch 'conventions' into 'master'
  • Loading branch information
henkmollema committed May 20, 2014
2 parents 7c4392c + e7ce65c commit e935638
Show file tree
Hide file tree
Showing 22 changed files with 741 additions and 111 deletions.
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ This [Dapper](https://github.com/SamSaffron/dapper-dot-net/) extension allows yo
<hr>

### Usage
Mapping properties:
```
#### Mapping properties using `EntityMap<TEntity>`
```csharp
public class ProductMap : EntityMap<Product>
{
public ProductMap()
Expand All @@ -27,13 +27,54 @@ public class ProductMap : EntityMap<Product>
}
```

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<int>()
.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<string>()
.Configure(c => c.HasPrefix("str"));

// Prefix all properties of type int with 'int' when mapping to column names.
Properties<int>()
.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<Product>()
.ForEntity<Order>;

// 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");
});
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file added nuget/Dapper.FluentMap.1.1.0.nupkg
Binary file not shown.
142 changes: 142 additions & 0 deletions src/Dapper.FluentMap/Configuration/FluentConventionConfiguration.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Defines methods for configuring conventions.
/// </summary>
public class FluentConventionConfiguration
{
private readonly Convention _convention;

/// <summary>
/// Initializes a new instance of the <see cref="FluentConventionConfiguration"/> class,
/// allowing configuration of conventions.
/// </summary>
/// <param name="convention">The convention.</param>
public FluentConventionConfiguration(Convention convention)
{
_convention = convention;
}

/// <summary>
/// Configures the current covention for the specified entity type.
/// </summary>
/// <typeparam name="T">The type of the entity.</typeparam>
/// <returns>The current instance of <see cref="T:Dapper.FluentMap.Conventions.FluentMapConventionConfiguration"/>.</returns>
public FluentConventionConfiguration ForEntity<T>()
{
Type type = typeof (T);
MapProperties(type);

FluentMapper.TypeConventions.AddOrUpdate(type, _convention);
FluentMapper.AddConventionTypeMap<T>();
return this;
}

/// <summary>
/// Configures the current convention for all the entities in current assembly filtered by the specified namespaces.
/// </summary>
/// <param name="namespaces">An array of namespaces which filter the types in the current assembly. This parameter is optional.</param>
/// <returns>The current instance of <see cref="T:Dapper.FluentMap.Conventions.FluentMapConventionConfiguration"/>.</returns>
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;
}

/// <summary>
/// Configures the current convention for all entities in the specified assembly filtered by the specified namespaces.
/// </summary>
/// <param name="assembly">The assembly to scan for entities.</param>
/// <param name="namespaces">An array of namespaces which filter the types in <paramref name="assembly"/>. This parameter is optional.</param>
/// <returns>The current instance of <see cref="T:Dapper.FluentMap.Conventions.FluentMapConventionConfiguration"/>.</returns>
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
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
return base.ToString();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
return base.Equals(obj);
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return base.GetHashCode();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public new Type GetType()
{
return base.GetType();
}
#endregion
}
}
67 changes: 67 additions & 0 deletions src/Dapper.FluentMap/Configuration/FluentMapConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.ComponentModel;
using Dapper.FluentMap.Conventions;
using Dapper.FluentMap.Mapping;

namespace Dapper.FluentMap.Configuration
{
/// <summary>
/// Defines methods for configuring Dapper.FluentMap.
/// </summary>
public class FluentMapConfiguration
{
/// <summary>
/// Adds the specified <see cref="T:Dapper.FluentMap.Mapping.EntityMap"/> to the configuration of Dapper.FluentMap.
/// </summary>
/// <typeparam name="TEntity">The type argument of the entity.</typeparam>
/// <param name="mapper">An instance of the EntityMap classs containing the entity mapping configuration.</param>
public void AddMap<TEntity>(EntityMap<TEntity> mapper) where TEntity : class
{
FluentMapper.EntityMappers.Add(typeof (TEntity), mapper);
FluentMapper.AddTypeMap<TEntity>();
}

/// <summary>
/// Adds the specified <see cref="T:Dapper.FluentMap.Conventions.Convention"/> to the configuration of Dapper.FluentMap.
/// </summary>
/// <param name="convention">An instance of the <see cref="T:Dapper.FluentMap.Conventions.Convention"/> class.</param>
/// <returns>
/// An instance of <see cref="T:Dapper.FluentMap.Conventions.FluentMapConventionConfiguration"/>
/// which allows configuration of the convention.
/// </returns>
public FluentConventionConfiguration AddConvention(Convention convention)
{
return new FluentConventionConfiguration(convention);
}

#region EditorBrowsableStates
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
return base.ToString();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
return base.Equals(obj);
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return base.GetHashCode();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public new Type GetType()
{
return base.GetType();
}
#endregion
}
}
83 changes: 83 additions & 0 deletions src/Dapper.FluentMap/Conventions/Convention.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Dapper.FluentMap.Mapping;

namespace Dapper.FluentMap.Conventions
{
/// <summary>
/// Represents a convention for mapping entity properties to column names.
/// </summary>
public abstract class Convention
{
/// <summary>
/// Initializes a new instance of the <see cref="T:Dapper.FluentMap.Conventions.Convention"/> class.
/// </summary>
protected Convention()
{
ConventionConfigurations = new List<PropertyConventionConfiguration>();
PropertyMaps = new List<PropertyMap>();
}

internal IList<PropertyConventionConfiguration> ConventionConfigurations { get; private set; }

internal IList<PropertyMap> PropertyMaps { get; private set; }

/// <summary>
/// Configures a convention that applies on all properties of the entity.
/// </summary>
/// <returns>A configuration object for the convention.</returns>
protected PropertyConventionConfiguration Properties()
{
var config = new PropertyConventionConfiguration();
ConventionConfigurations.Add(config);

return config;
}

/// <summary>
/// Configures a convention that applies on all the properties of a specified type of the entity.
/// </summary>
/// <typeparam name="T">The type of the properties that the convention will apply to.</typeparam>
/// <returns>A configuration object for the convention.</returns>
protected PropertyConventionConfiguration Properties<T>()
{
// 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
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
return base.ToString();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
return base.Equals(obj);
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return base.GetHashCode();
}

/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public new Type GetType()
{
return base.GetType();
}
#endregion
}
}
Loading

0 comments on commit e935638

Please sign in to comment.