using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using Marr.Data.Mapping.Strategies; using System.Collections; namespace Marr.Data.Mapping { /// <summary> /// Provides a fluent interface for mapping domain entities and properties to database tables and columns. /// </summary> public class FluentMappings { private bool _publicOnly; public FluentMappings() : this(true) { } public FluentMappings(bool publicOnly) { _publicOnly = publicOnly; } public MappingsFluentEntity<TEntity> Entity<TEntity>() { return new MappingsFluentEntity<TEntity>(_publicOnly); } public class MappingsFluentEntity<TEntity> { public MappingsFluentEntity(bool publicOnly) { Columns = new MappingsFluentColumns<TEntity>(this, publicOnly); Table = new MappingsFluentTables<TEntity>(this); Relationships = new MappingsFluentRelationships<TEntity>(this, publicOnly); } /// <summary> /// Contains methods that map entity properties to database table and view column names; /// </summary> public MappingsFluentColumns<TEntity> Columns { get; private set; } /// <summary> /// Contains methods that map entity classes to database table names. /// </summary> public MappingsFluentTables<TEntity> Table { get; private set; } /// <summary> /// Contains methods that map sub-entities with database table and view column names. /// </summary> public MappingsFluentRelationships<TEntity> Relationships { get; private set; } } public class MappingsFluentColumns<TEntity> { private bool _publicOnly; private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity; public MappingsFluentColumns(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, bool publicOnly) { _fluentEntity = fluentEntity; _publicOnly = publicOnly; } /// <summary> /// Creates column mappings for the given type. /// Maps all properties except ICollection properties. /// </summary> /// <typeparam name="T">The type that is being built.</typeparam> /// <returns><see cref="ColumnMapCollection"/></returns> public ColumnMapBuilder<TEntity> AutoMapAllProperties() { return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property && !typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType)); } /// <summary> /// Creates column mappings for the given type. /// Maps all properties that are simple types (int, string, DateTime, etc). /// ICollection properties are not included. /// </summary> /// <typeparam name="T">The type that is being built.</typeparam> /// <returns><see cref="ColumnMapCollection"/></returns> public ColumnMapBuilder<TEntity> AutoMapSimpleTypeProperties() { return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property && DataHelper.IsSimpleType((m as PropertyInfo).PropertyType) && !typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType)); } /// <summary> /// Creates column mappings for the given type if they match the predicate. /// </summary> /// <typeparam name="T">The type that is being built.</typeparam> /// <param name="predicate">Determines whether a mapping should be created based on the member info.</param> /// <returns><see cref="ColumnMapConfigurator"/></returns> public ColumnMapBuilder<TEntity> AutoMapPropertiesWhere(Func<MemberInfo, bool> predicate) { Type entityType = typeof(TEntity); ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly); strategy.ColumnPredicate = predicate; ColumnMapCollection columns = strategy.MapColumns(entityType); MapRepository.Instance.Columns[entityType] = columns; return new ColumnMapBuilder<TEntity>(_fluentEntity, columns); } /// <summary> /// Creates a ColumnMapBuilder that starts out with no pre-populated columns. /// All columns must be added manually using the builder. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public ColumnMapBuilder<TEntity> MapProperties() { Type entityType = typeof(TEntity); ColumnMapCollection columns = new ColumnMapCollection(); MapRepository.Instance.Columns[entityType] = columns; return new ColumnMapBuilder<TEntity>(_fluentEntity, columns); } } public class MappingsFluentTables<TEntity> { private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity; public MappingsFluentTables(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity) { _fluentEntity = fluentEntity; } /// <summary> /// Provides a fluent table mapping interface. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public TableBuilder<TEntity> AutoMapTable<T>() { return new TableBuilder<TEntity>(_fluentEntity); } /// <summary> /// Sets the table name for a given type. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="tableName"></param> public TableBuilder<TEntity> MapTable(string tableName) { return new TableBuilder<TEntity>(_fluentEntity).SetTableName(tableName); } } public class MappingsFluentRelationships<TEntity> { private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity; private bool _publicOnly; public MappingsFluentRelationships(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, bool publicOnly) { _fluentEntity = fluentEntity; _publicOnly = publicOnly; } /// <summary> /// Creates relationship mappings for the given type. /// Maps all properties that implement ICollection or are not "simple types". /// </summary> /// <returns></returns> public RelationshipBuilder<TEntity> AutoMapICollectionOrComplexProperties() { return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property && ( typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType) || !DataHelper.IsSimpleType((m as PropertyInfo).PropertyType) ) ); } /// <summary> /// Creates relationship mappings for the given type. /// Maps all properties that implement ICollection. /// </summary> /// <returns><see cref="RelationshipBuilder"/></returns> public RelationshipBuilder<TEntity> AutoMapICollectionProperties() { return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property && typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType)); } /// <summary> /// Creates relationship mappings for the given type. /// Maps all properties that are not "simple types". /// </summary> /// <returns></returns> public RelationshipBuilder<TEntity> AutoMapComplexTypeProperties<T>() { return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property && !DataHelper.IsSimpleType((m as PropertyInfo).PropertyType)); } /// <summary> /// Creates relationship mappings for the given type if they match the predicate. /// </summary> /// <param name="predicate">Determines whether a mapping should be created based on the member info.</param> /// <returns><see cref="RelationshipBuilder"/></returns> public RelationshipBuilder<TEntity> AutoMapPropertiesWhere(Func<MemberInfo, bool> predicate) { Type entityType = typeof(TEntity); ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly); strategy.RelationshipPredicate = predicate; RelationshipCollection relationships = strategy.MapRelationships(entityType); MapRepository.Instance.Relationships[entityType] = relationships; return new RelationshipBuilder<TEntity>(_fluentEntity, relationships); } /// <summary> /// Creates a RelationshipBuilder that starts out with no pre-populated relationships. /// All relationships must be added manually using the builder. /// </summary> /// <returns></returns> public RelationshipBuilder<TEntity> MapProperties<T>() { Type entityType = typeof(T); RelationshipCollection relationships = new RelationshipCollection(); MapRepository.Instance.Relationships[entityType] = relationships; return new RelationshipBuilder<TEntity>(_fluentEntity, relationships); } } } }