using System; using System.Linq; using System.Linq.Expressions; using Marr.Data.Mapping.Strategies; namespace Marr.Data.Mapping { /// /// This class has fluent methods that are used to easily configure relationship mappings. /// /// public class RelationshipBuilder { private FluentMappings.MappingsFluentEntity _fluentEntity; private string _currentPropertyName; public RelationshipBuilder(FluentMappings.MappingsFluentEntity fluentEntity, RelationshipCollection relationships) { _fluentEntity = fluentEntity; Relationships = relationships; } /// /// Gets the list of relationship mappings that are being configured. /// public RelationshipCollection Relationships { get; private set; } #region - Fluent Methods - /// /// Initializes the configurator to configure the given property. /// /// /// public RelationshipBuilder For(Expression> property) { return For(property.GetMemberName()); } /// /// Initializes the configurator to configure the given property or field. /// /// /// public RelationshipBuilder For(string propertyName) { _currentPropertyName = propertyName; // Try to add the relationship if it doesn't exist if (Relationships[_currentPropertyName] == null) { TryAddRelationshipForField(_currentPropertyName); } return this; } /// /// Sets a property to be lazy loaded, with a given query. /// /// /// /// condition in which a child could exist. eg. avoid call to db if foreign key is 0 or null /// public RelationshipBuilder LazyLoad(Func query, Func condition = null) { AssertCurrentPropertyIsSet(); Relationships[_currentPropertyName].LazyLoaded = new LazyLoaded(query, condition); return this; } public RelationshipBuilder SetOneToOne() { AssertCurrentPropertyIsSet(); SetOneToOne(_currentPropertyName); return this; } public RelationshipBuilder SetOneToOne(string propertyName) { Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.One; return this; } public RelationshipBuilder SetOneToMany() { AssertCurrentPropertyIsSet(); SetOneToMany(_currentPropertyName); return this; } public RelationshipBuilder SetOneToMany(string propertyName) { Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.Many; return this; } public RelationshipBuilder Ignore(Expression> property) { string propertyName = property.GetMemberName(); Relationships.RemoveAll(r => r.Member.Name == propertyName); return this; } public FluentMappings.MappingsFluentTables Tables { get { if (_fluentEntity == null) { throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class."); } return _fluentEntity.Table; } } public FluentMappings.MappingsFluentColumns Columns { get { if (_fluentEntity == null) { throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class."); } return _fluentEntity.Columns; } } public FluentMappings.MappingsFluentEntity Entity() { return new FluentMappings.MappingsFluentEntity(true); } /// /// Tries to add a Relationship for the given field name. /// Throws and exception if field cannot be found. /// 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)); } Relationships.Add(relationship); } /// /// Throws an exception if the "current" property has not been set. /// private void AssertCurrentPropertyIsSet() { if (string.IsNullOrEmpty(_currentPropertyName)) { throw new DataMappingException("A property must first be specified using the 'For' method."); } } #endregion } }