2013-03-30 22:56:34 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using Marr.Data.Mapping.Strategies;
|
|
|
|
|
|
|
|
|
|
namespace Marr.Data.Mapping
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This class has fluent methods that are used to easily configure relationship mappings.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="TEntity"></typeparam>
|
|
|
|
|
public class RelationshipBuilder<TEntity>
|
|
|
|
|
{
|
|
|
|
|
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
|
|
|
|
private string _currentPropertyName;
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, RelationshipCollection relationships)
|
|
|
|
|
{
|
|
|
|
|
_fluentEntity = fluentEntity;
|
|
|
|
|
Relationships = relationships;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the list of relationship mappings that are being configured.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public RelationshipCollection Relationships { get; private set; }
|
|
|
|
|
|
|
|
|
|
#region - Fluent Methods -
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes the configurator to configure the given property.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="property"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public RelationshipBuilder<TEntity> For(Expression<Func<TEntity, object>> property)
|
|
|
|
|
{
|
|
|
|
|
return For(property.GetMemberName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes the configurator to configure the given property or field.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="propertyName"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public RelationshipBuilder<TEntity> For(string propertyName)
|
|
|
|
|
{
|
|
|
|
|
_currentPropertyName = propertyName;
|
|
|
|
|
|
|
|
|
|
// Try to add the relationship if it doesn't exist
|
|
|
|
|
if (Relationships[_currentPropertyName] == null)
|
|
|
|
|
{
|
|
|
|
|
TryAddRelationshipForField(_currentPropertyName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets a property to be lazy loaded, with a given query.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="TChild"></typeparam>
|
|
|
|
|
/// <param name="query"></param>
|
2013-05-22 07:30:54 +02:00
|
|
|
|
/// <param name="condition">condition in which a child could exist. eg. avoid call to db if foreign key is 0 or null</param>
|
2013-03-30 22:56:34 +01:00
|
|
|
|
/// <returns></returns>
|
2013-05-22 07:30:54 +02:00
|
|
|
|
public RelationshipBuilder<TEntity> LazyLoad<TChild>(Func<IDataMapper, TEntity, TChild> query, Func<TEntity, bool> condition = null)
|
2013-03-30 22:56:34 +01:00
|
|
|
|
{
|
|
|
|
|
AssertCurrentPropertyIsSet();
|
|
|
|
|
|
2013-05-22 07:30:54 +02:00
|
|
|
|
Relationships[_currentPropertyName].LazyLoaded = new LazyLoaded<TEntity, TChild>(query, condition);
|
2013-03-30 22:56:34 +01:00
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder<TEntity> SetOneToOne()
|
|
|
|
|
{
|
|
|
|
|
AssertCurrentPropertyIsSet();
|
|
|
|
|
SetOneToOne(_currentPropertyName);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder<TEntity> SetOneToOne(string propertyName)
|
|
|
|
|
{
|
|
|
|
|
Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.One;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder<TEntity> SetOneToMany()
|
|
|
|
|
{
|
|
|
|
|
AssertCurrentPropertyIsSet();
|
|
|
|
|
SetOneToMany(_currentPropertyName);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder<TEntity> SetOneToMany(string propertyName)
|
|
|
|
|
{
|
|
|
|
|
Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.Many;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RelationshipBuilder<TEntity> Ignore(Expression<Func<TEntity, object>> property)
|
|
|
|
|
{
|
|
|
|
|
string propertyName = property.GetMemberName();
|
|
|
|
|
Relationships.RemoveAll(r => r.Member.Name == propertyName);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FluentMappings.MappingsFluentTables<TEntity> Tables
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_fluentEntity == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _fluentEntity.Table;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FluentMappings.MappingsFluentColumns<TEntity> Columns
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_fluentEntity == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _fluentEntity.Columns;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FluentMappings.MappingsFluentEntity<TNewEntity> Entity<TNewEntity>()
|
|
|
|
|
{
|
|
|
|
|
return new FluentMappings.MappingsFluentEntity<TNewEntity>(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Tries to add a Relationship for the given field name.
|
|
|
|
|
/// Throws and exception if field cannot be found.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void TryAddRelationshipForField(string fieldName)
|
|
|
|
|
{
|
|
|
|
|
// Set strategy to filter for public or private fields
|
|
|
|
|
ConventionMapStrategy strategy = new ConventionMapStrategy(false);
|
|
|
|
|
|
|
|
|
|
// Find the field that matches the given field name
|
|
|
|
|
strategy.RelationshipPredicate = mi => mi.Name == fieldName;
|
|
|
|
|
Relationship relationship = strategy.MapRelationships(typeof(TEntity)).FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
if (relationship == null)
|
|
|
|
|
{
|
|
|
|
|
throw new DataMappingException(string.Format("Could not find the field '{0}' in '{1}'.",
|
|
|
|
|
fieldName,
|
|
|
|
|
typeof(TEntity).Name));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Relationships.Add(relationship);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Throws an exception if the "current" property has not been set.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void AssertCurrentPropertyIsSet()
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(_currentPropertyName))
|
|
|
|
|
{
|
|
|
|
|
throw new DataMappingException("A property must first be specified using the 'For' method.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|