/// <summary> /// Dispatches the call to the extensions. /// </summary> /// <param name="pi">The property info reflection object.</param> /// <param name="hasManyModel">The has many model.</param> /// <param name="model">The model.</param> public void ProcessHasMany(PropertyInfo pi, HasManyModel hasManyModel, ActiveRecordModel model) { foreach (IModelBuilderExtension extension in extensions) { extension.ProcessHasMany(pi, hasManyModel, model); } }
public override void VisitHasMany(HasManyModel model) { HasManyAttribute att = model.HasManyAtt; WriteCollection(att.Cascade, att.MapType, att.RelationType, model.Property.Name, model.HasManyAtt.AccessString, att.Table, att.Schema, att.Lazy, att.Inverse, att.OrderBy, att.Where, att.Sort, att.ColumnKey, null, null, att.Index, att.IndexType, att.Cache); }
private static void ProcessProperties(Type type, ActiveRecordModel model) { // Check persistent properties of the base class as well if (ShouldCheckBase(type)) { ProcessProperties(type.BaseType, model); } PropertyInfo[] props = type.GetProperties(DefaultBindingFlags); foreach (PropertyInfo prop in props) { bool isArProperty = false; AnyModel anyModel; HasManyToAnyModel hasManyToAnyModel; object[] valAtts = prop.GetCustomAttributes(typeof(AbstractValidationAttribute), true); foreach (AbstractValidationAttribute valAtt in valAtts) { IValidator validator = valAtt.Build(); validator.Initialize(validatorRegistry, prop); model.Validators.Add(validator); } foreach (object attribute in prop.GetCustomAttributes(false)) { if (attribute is PrimaryKeyAttribute) { PrimaryKeyAttribute propAtt = attribute as PrimaryKeyAttribute; isArProperty = true; // Joined Subclasses must not have PrimaryKey if (type.IsDefined(typeof(JoinedBaseAttribute), true) && // JoinedBase in a superclass !type.IsDefined(typeof(JoinedBaseAttribute), false)) // but not here { throw new ActiveRecordException("You can't specify a PrimaryKeyAttribute in a joined subclass. " + "Check type " + model.Type.FullName); } if (prop.PropertyType.IsDefined(typeof(CompositeKeyAttribute), true)) { object[] att = prop.PropertyType.GetCustomAttributes(typeof(CompositeKeyAttribute), true); CompositeKeyAttribute cAtt = att[0] as CompositeKeyAttribute; model.CompositeKey = new CompositeKeyModel(prop, cAtt); } else { model.PrimaryKey = new PrimaryKeyModel(prop, propAtt); } } else if (attribute is CompositeKeyAttribute) { CompositeKeyAttribute propAtt = attribute as CompositeKeyAttribute; isArProperty = true; model.CompositeKey = new CompositeKeyModel(prop, propAtt); } else if (attribute is AnyAttribute) { AnyAttribute anyAtt = attribute as AnyAttribute; isArProperty = true; anyModel = new AnyModel(prop, anyAtt); model.Anys.Add(anyModel); CollectMetaValues(anyModel.MetaValues, prop); } else if (attribute is PropertyAttribute) { PropertyAttribute propAtt = attribute as PropertyAttribute; isArProperty = true; model.Properties.Add(new PropertyModel(prop, propAtt)); } else if (attribute is NestedAttribute) { NestedAttribute propAtt = attribute as NestedAttribute; isArProperty = true; ActiveRecordModel nestedModel = new ActiveRecordModel(prop.PropertyType); nestedModel.IsNestedType = true; Type nestedType = propAtt.MapType != null ? propAtt.MapType : prop.PropertyType; nestedModel.IsNestedCompositeType = model.IsNestedCompositeType; ProcessProperties(nestedType, nestedModel); ProcessFields(nestedType, nestedModel); model.Components.Add(new NestedModel(prop, propAtt, nestedModel)); } else if (attribute is NestedParentReferenceAttribute) { NestedParentReferenceAttribute nestedParentAtt = attribute as NestedParentReferenceAttribute; isArProperty = true; model.ComponentParent.Add(new NestedParentReferenceModel(prop, nestedParentAtt)); } else if (attribute is JoinedKeyAttribute) { JoinedKeyAttribute propAtt = attribute as JoinedKeyAttribute; isArProperty = true; if (model.Key != null) { throw new ActiveRecordException("You can't specify more than one JoinedKeyAttribute. " + "Check type " + model.Type.FullName); } model.Key = new KeyModel(prop, propAtt); } else if (attribute is VersionAttribute) { VersionAttribute propAtt = attribute as VersionAttribute; isArProperty = true; if (model.Version != null) { throw new ActiveRecordException("You can't specify more than one VersionAttribute. " + "Check type " + model.Type.FullName); } model.Version = new VersionModel(prop, propAtt); } else if (attribute is TimestampAttribute) { TimestampAttribute propAtt = attribute as TimestampAttribute; isArProperty = true; if (model.Timestamp != null) { throw new ActiveRecordException("You can't specify more than one TimestampAttribute. " + "Check type " + model.Type.FullName); } model.Timestamp = new TimestampModel(prop, propAtt); } // Relations else if (attribute is OneToOneAttribute) { OneToOneAttribute propAtt = attribute as OneToOneAttribute; isArProperty = true; model.OneToOnes.Add(new OneToOneModel(prop, propAtt)); } else if (attribute is BelongsToAttribute) { BelongsToAttribute propAtt = attribute as BelongsToAttribute; isArProperty = true; model.BelongsTo.Add(new BelongsToModel(prop, propAtt)); } // The ordering is important here, HasManyToAny must comes before HasMany! else if (attribute is HasManyToAnyAttribute) { HasManyToAnyAttribute propAtt = attribute as HasManyToAnyAttribute; isArProperty = true; hasManyToAnyModel = new HasManyToAnyModel(prop, propAtt); model.HasManyToAny.Add(hasManyToAnyModel); CollectMetaValues(hasManyToAnyModel.MetaValues, prop); } else if (attribute is HasManyAttribute) { HasManyAttribute propAtt = attribute as HasManyAttribute; isArProperty = true; HasManyModel hasManyModel = new HasManyModel(prop, propAtt); if (propAtt.DependentObjects) { ActiveRecordModel dependentObjectModel = new ActiveRecordModel(propAtt.MapType); dependentObjectModel.IsNestedType = true; dependentObjectModel.IsNestedCompositeType = true; ProcessProperties(propAtt.MapType, dependentObjectModel); hasManyModel.DependentObjectModel = new DependentObjectModel(prop, propAtt, dependentObjectModel); } model.HasMany.Add(hasManyModel); } else if (attribute is HasAndBelongsToManyAttribute) { HasAndBelongsToManyAttribute propAtt = attribute as HasAndBelongsToManyAttribute; isArProperty = true; model.HasAndBelongsToMany.Add(new HasAndBelongsToManyModel(prop, propAtt)); } else if (attribute is Any.MetaValueAttribute) { if (prop.GetCustomAttributes(typeof(HasManyToAnyAttribute), false).Length == 0 && prop.GetCustomAttributes(typeof(AnyAttribute), false).Length == 0 ) throw new ActiveRecordException( "You can't specify an Any.MetaValue without specifying the Any or HasManyToAny attribute. " + "Check type " + prop.DeclaringType.FullName); } else if (attribute is CompositeUserTypeAttribute) { CompositeUserTypeAttribute propAtt = attribute as CompositeUserTypeAttribute; isArProperty = true; model.CompositeUserType.Add(new CompositeUserTypeModel(prop, propAtt)); } if (attribute is CollectionIDAttribute) { CollectionIDAttribute propAtt = attribute as CollectionIDAttribute; model.CollectionIDs.Add(new CollectionIDModel(prop, propAtt)); } if (attribute is HiloAttribute) { HiloAttribute propAtt = attribute as HiloAttribute; model.Hilos.Add(new HiloModel(prop, propAtt)); } } if (!isArProperty) { model.NotMappedProperties.Add(prop); } } }
/// <summary> /// Dispatches the call to the extensions. /// </summary> /// <param name="pi">The property info reflection object.</param> /// <param name="hasManyModel">The has many model.</param> /// <param name="model">The model.</param> public void ProcessHasMany(PropertyInfo pi, HasManyModel hasManyModel, ActiveRecordModel model) { foreach(IModelBuilderExtension extension in extensions) { extension.ProcessHasMany(pi, hasManyModel, model); } }
/// <summary> /// Guesses the element mapping based on enum. /// </summary> /// <param name="model">The model.</param> private static void GuessElementMappingBasedOnEnum(HasManyModel model) { model.HasManyAtt.ElementType = model.HasManyAtt.MapType; model.HasManyAtt.Element = string.Format("{0}Id", model.HasManyAtt.MapType.Name); model.HasManyAtt.ColumnKey = string.Format("{0}Id", model.Property.DeclaringType.Name); }
/// <summary> /// Visits the has many. /// </summary> /// <remarks> /// Guess the type of the relation, if not specified explicitly /// Verify that the assoication is valid on [HasMany] /// Validate that required information is specified /// Infer the other side of the assoication and grab require data from it /// </remarks> /// <param name="model">The model.</param> public override void VisitHasMany(HasManyModel model) { if (model.HasManyAtt.MapType == null) model.HasManyAtt.MapType = GuessType(null, model.Property.PropertyType); model.HasManyAtt.RelationType = GuessRelation(model.Property, model.HasManyAtt.RelationType); // Guess the details about a map relation if needed if (model.HasManyAtt.RelationType == RelationType.Map) { if (string.IsNullOrEmpty(model.HasManyAtt.Table)) { model.HasManyAtt.Table = string.Format("{0}_{1}", model.Property.ReflectedType.Name, model.Property.Name); } if (model.HasManyAtt.IndexType == null) { model.HasManyAtt.IndexType = GetIndexTypeFromDictionary(model.Property.PropertyType).Name; } if (model.HasManyAtt.MapType == null) { model.HasManyAtt.MapType = GetMapTypeFromDictionary(model.Property.PropertyType); } } if (model.HasManyAtt.RelationType == RelationType.IdBag) { throw new ActiveRecordException(String.Format( "You can't use idbags in a many to one association (HasMany) {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } if (model.HasManyAtt.RelationType == RelationType.Map && model.HasManyAtt.Index == null) { throw new ActiveRecordException(String.Format( "A HasMany with type Map requires that you specify an 'Index', use the Index property {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } if (model.HasManyAtt.RelationType == RelationType.List && model.HasManyAtt.Index == null) { throw new ActiveRecordException(String.Format( "A HasMany with type List requires that you specify an 'Index', use the Index property {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } // try to guess an <element> mapping if none of the mapping properties was set if (model.HasManyAtt.MapType.IsValueType && string.IsNullOrEmpty(model.HasManyAtt.Element) && model.HasManyAtt.ElementType == null && string.IsNullOrEmpty(model.HasManyAtt.ColumnKey)) { GuessElementMappingBasedOnEnum(model); } // Infer table and column based on possible belongs to // on the target class String table = model.HasManyAtt.Table; String keyColumn = model.HasManyAtt.ColumnKey; String[] compositeKeyColumnKeys = model.HasManyAtt.CompositeKeyColumnKeys; Type type = model.HasManyAtt.MapType; ActiveRecordModel target = arCollection[type]; if ((table == null || (keyColumn == null && compositeKeyColumnKeys == null)) && target == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find information about the specified target type {2}. If you have mapped a Collection or Dictionary of value types, please make sure you have specified the Table property.", model.Property.DeclaringType.Name, model.Property.Name, type)); } BelongsToModel targetBtModel = null; ActiveRecordModel tmpModel = target; while (tmpModel != null && targetBtModel == null) { foreach (BelongsToModel btModel in tmpModel.BelongsTo) { if (btModel.BelongsToAtt.Type != model.Property.DeclaringType && btModel.BelongsToAtt.Type != model.ContainingTypeModel.Type && btModel.Property.PropertyType != model.Property.DeclaringType && btModel.Property.PropertyType != model.ContainingTypeModel.Type) continue; targetBtModel = btModel; break; } tmpModel = tmpModel.Parent; } if ((table == null || (keyColumn == null && compositeKeyColumnKeys == null)) && targetBtModel == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find a 'BelongsTo' mapped property in the target type {2}", model.Property.DeclaringType.Name, model.Property.Name, type)); } if (target != null) { VisitModel(target); } else if (model.HasManyAtt.DependentObjects) { VisitDependentObject(model.DependentObjectModel); } if (table == null) { table = target.ActiveRecordAtt.Table; } if (targetBtModel != null) { if (keyColumn == null && targetBtModel.BelongsToAtt.CompositeKeyColumns == null) { keyColumn = targetBtModel.BelongsToAtt.Column; } else { compositeKeyColumnKeys = targetBtModel.BelongsToAtt.CompositeKeyColumns; } } model.HasManyAtt.Table = table; if (keyColumn != null) { model.HasManyAtt.ColumnKey = keyColumn; } else { model.HasManyAtt.CompositeKeyColumnKeys = compositeKeyColumnKeys; } }
/// <summary> /// Visits the has many. /// </summary> /// <param name="model">The model.</param> public override void VisitHasMany(HasManyModel model) { HasManyAttribute att = model.HasManyAtt; Type mapType = GuessType(att.MapType, model.Property.PropertyType); WriteCollection(att.Cascade, mapType, att.RelationType, model.Property.Name, model.HasManyAtt.AccessString, att.Table, att.Schema, att.Lazy, att.Inverse, att.OrderBy, att.Where, att.Sort, att.ColumnKey, att.CompositeKeyColumnKeys, att.Element, att.ElementType, null, null, model.DependentObjectModel, att.Index, att.IndexType, att.Cache, att.CacheRegion, att.NotFoundBehaviour, att.Fetch, att.BatchSize, att.CollectionType); }
private void ProcessProperties(Type type, ActiveRecordModel model) { // Check persistent properties of the base class as well if (ShouldCheckBase(type)) { ProcessProperties(type.BaseType, model); } PropertyInfo[] props = type.GetProperties(DefaultBindingFlags); foreach (PropertyInfo prop in props) { bool isArProperty = false; AnyModel anyModel; HasManyToAnyModel hasManyToAnyModel; if (extension != null) { extension.ProcessProperty(prop, model); } object[] valAtts = prop.GetCustomAttributes(typeof(AbstractValidationAttribute), true); foreach (AbstractValidationAttribute valAtt in valAtts) { IValidator validator = valAtt.Build(); validator.Initialize(validatorRegistry, prop); model.Validators.Add(validator); } foreach (object attribute in prop.GetCustomAttributes(false)) { if (attribute is PrimaryKeyAttribute) { PrimaryKeyAttribute propAtt = attribute as PrimaryKeyAttribute; isArProperty = true; // Joined Subclasses must not have PrimaryKey if (HasJoinedBase(type)) { throw new ActiveRecordException("You can't specify a PrimaryKeyAttribute in a joined subclass. " + "Check type " + model.Type.FullName); } if (prop.PropertyType.IsDefined(typeof(CompositeKeyAttribute), true)) { object[] att = prop.PropertyType.GetCustomAttributes(typeof(CompositeKeyAttribute), true); CompositeKeyAttribute cAtt = att[0] as CompositeKeyAttribute; model.CompositeKey = new CompositeKeyModel(prop, cAtt); } else { if (!propAtt.IsOverride && model.PrimaryKey != null) { throw new ActiveRecordException("You can't specify more than one PrimaryKeyAttribute in a " + "class. Check type " + model.Type.FullName); } model.PrimaryKey = new PrimaryKeyModel(prop, propAtt); } } else if (attribute is CompositeKeyAttribute) { CompositeKeyAttribute propAtt = attribute as CompositeKeyAttribute; isArProperty = true; model.CompositeKey = new CompositeKeyModel(prop, propAtt); } else if (attribute is AnyAttribute) { AnyAttribute anyAtt = attribute as AnyAttribute; isArProperty = true; anyModel = new AnyModel(prop, anyAtt); model.Anys.Add(anyModel); CollectMetaValues(anyModel.MetaValues, prop); } else if (attribute is PropertyAttribute) { PropertyAttribute propAtt = attribute as PropertyAttribute; isArProperty = true; // If this property overrides a base class property remove the old one if (propAtt.IsOverride) { for (int index = 0; index < model.Properties.Count; ++index) { PropertyModel oldModel = (PropertyModel)model.Properties[index]; if (oldModel.Property.Name == prop.Name) { model.Properties.RemoveAt(index); break; } } } PropertyModel propModel = new PropertyModel(prop, propAtt); model.Properties.Add(propModel); model.PropertyDictionary[prop.Name] = propModel; } else if (attribute is NestedAttribute) { NestedAttribute propAtt = attribute as NestedAttribute; isArProperty = true; ActiveRecordModel nestedModel = new ActiveRecordModel(prop.PropertyType); nestedModel.IsNestedType = true; Type nestedType = propAtt.MapType ?? prop.PropertyType; nestedModel.IsNestedCompositeType = model.IsNestedCompositeType; ProcessProperties(nestedType, nestedModel); ProcessFields(nestedType, nestedModel); NestedModel nested = new NestedModel(prop, propAtt, nestedModel); nestedModel.ParentNested = nested; model.Components.Add(nested); } else if (attribute is NestedParentReferenceAttribute) { NestedParentReferenceAttribute nestedParentAtt = attribute as NestedParentReferenceAttribute; isArProperty = true; model.ComponentParent.Add(new NestedParentReferenceModel(prop, nestedParentAtt)); } else if (attribute is JoinedKeyAttribute) { JoinedKeyAttribute propAtt = attribute as JoinedKeyAttribute; isArProperty = true; if (model.Key != null) { throw new ActiveRecordException("You can't specify more than one JoinedKeyAttribute. " + "Check type " + model.Type.FullName); } model.Key = new KeyModel(prop, propAtt); } else if (attribute is VersionAttribute) { VersionAttribute propAtt = attribute as VersionAttribute; isArProperty = true; if (model.Version != null) { throw new ActiveRecordException("You can't specify more than one VersionAttribute. " + "Check type " + model.Type.FullName); } model.Version = new VersionModel(prop, propAtt); } else if (attribute is TimestampAttribute) { TimestampAttribute propAtt = attribute as TimestampAttribute; isArProperty = true; if (model.Timestamp != null) { throw new ActiveRecordException("You can't specify more than one TimestampAttribute. " + "Check type " + model.Type.FullName); } model.Timestamp = new TimestampModel(prop, propAtt); } // Relations else if (attribute is OneToOneAttribute) { OneToOneAttribute propAtt = attribute as OneToOneAttribute; isArProperty = true; model.OneToOnes.Add(new OneToOneModel(prop, propAtt)); } else if (attribute is BelongsToAttribute) { BelongsToAttribute propAtt = attribute as BelongsToAttribute; isArProperty = true; BelongsToModel btModel = new BelongsToModel(prop, propAtt); model.BelongsTo.Add(btModel); model.BelongsToDictionary[prop.Name] = btModel; if (extension != null) { extension.ProcessBelongsTo(prop, btModel, model); } } // The ordering is important here, HasManyToAny must comes before HasMany! else if (attribute is HasManyToAnyAttribute) { HasManyToAnyAttribute propAtt = attribute as HasManyToAnyAttribute; isArProperty = true; hasManyToAnyModel = new HasManyToAnyModel(prop, propAtt); model.HasManyToAny.Add(hasManyToAnyModel); model.HasManyToAnyDictionary[prop.Name] = hasManyToAnyModel; CollectMetaValues(hasManyToAnyModel.MetaValues, prop); if (extension != null) { extension.ProcessHasManyToAny(prop, hasManyToAnyModel, model); } } else if (attribute is HasManyAttribute) { HasManyAttribute propAtt = attribute as HasManyAttribute; isArProperty = true; HasManyModel hasManyModel = new HasManyModel(prop, propAtt, model); if (propAtt.DependentObjects) { ActiveRecordModel dependentObjectModel = new ActiveRecordModel(propAtt.MapType); dependentObjectModel.IsNestedType = true; dependentObjectModel.IsNestedCompositeType = true; ProcessProperties(propAtt.MapType, dependentObjectModel); hasManyModel.DependentObjectModel = new DependentObjectModel(prop, propAtt, dependentObjectModel); } model.HasMany.Add(hasManyModel); model.HasManyDictionary[prop.Name] = hasManyModel; if (extension != null) { extension.ProcessHasMany(prop, hasManyModel, model); } } else if (attribute is HasAndBelongsToManyAttribute) { HasAndBelongsToManyAttribute propAtt = attribute as HasAndBelongsToManyAttribute; isArProperty = true; HasAndBelongsToManyModel habtManyModel = new HasAndBelongsToManyModel(prop, propAtt); model.HasAndBelongsToMany.Add(habtManyModel); model.HasAndBelongsToManyDictionary[prop.Name] = habtManyModel; if (extension != null) { extension.ProcessHasAndBelongsToMany(prop, habtManyModel, model); } } else if (attribute is Any.MetaValueAttribute) { if (prop.GetCustomAttributes(typeof(HasManyToAnyAttribute), false).Length == 0 && prop.GetCustomAttributes(typeof(AnyAttribute), false).Length == 0 ) { throw new ActiveRecordException( "You can't specify an Any.MetaValue without specifying the Any or HasManyToAny attribute. " + "Check type " + prop.DeclaringType.FullName); } } else if (attribute is CompositeUserTypeAttribute) { CompositeUserTypeAttribute propAtt = attribute as CompositeUserTypeAttribute; isArProperty = true; model.CompositeUserType.Add(new CompositeUserTypeModel(prop, prop.PropertyType, propAtt)); } if (attribute is CollectionIDAttribute) { CollectionIDAttribute propAtt = attribute as CollectionIDAttribute; model.CollectionIDs.Add(new CollectionIDModel(prop, propAtt)); } if (attribute is HiloAttribute) { HiloAttribute propAtt = attribute as HiloAttribute; model.Hilos.Add(new HiloModel(prop, propAtt)); } } if (!isArProperty) { model.NotMappedProperties.Add(prop); } } }
public virtual void VisitHasMany(HasManyModel model) { }
/// <summary> /// Visits the has many. /// </summary> /// <param name="model">The model.</param> public virtual void VisitHasMany(HasManyModel model) { }
public String CreateControl(ActiveRecordModel model, String prefix, HasManyModel hasManyModel, object instance) { stringBuilder.Length = 0; PropertyInfo prop = hasManyModel.Property; prefix += "." + prop.Name; ActiveRecordModel otherModel = ActiveRecordModel.GetModel(hasManyModel.HasManyAtt.MapType); PrimaryKeyModel keyModel = ObtainPKProperty(otherModel); if (otherModel == null || keyModel == null) { return "Model not found or PK not found"; } object[] source = CommonOperationUtils.FindAll(otherModel.Type); stringBuilder.Append(prop.Name + ": "); stringBuilder.Append("<br/>\r\n"); IDictionary attrs = new HybridDictionary(true); attrs["value"] = keyModel.Property.Name; FormHelper.CheckboxList list = CreateCheckboxList(prefix, source, attrs); foreach(object item in list) { stringBuilder.Append(list.Item()); stringBuilder.Append(item.ToString()); stringBuilder.Append("<br/>\r\n"); } return stringBuilder.ToString(); }
public bool CanHandle(HasManyModel model) { if (!model.HasManyAtt.Inverse) { return CheckModelAndKeyAreAccessible(model.HasManyAtt.MapType); } return false; }
public override void VisitHasMany(HasManyModel model) { model.HasManyAtt.RelationType = GuessRelation(model.Property, model.HasManyAtt.RelationType); if (model.HasManyAtt.RelationType == RelationType.IdBag) { throw new ActiveRecordException(String.Format( "You can't use idbags in a many to one association (HasMany) {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } if (model.HasManyAtt.RelationType == RelationType.Map && model.HasManyAtt.Index == null) { throw new ActiveRecordException(String.Format( "A HasMany with type Map requires that you specify an 'Index', use the Index property {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } // Infer table and column based on possible belongs to // on the target class String table = model.HasManyAtt.Table; String keyColumn = model.HasManyAtt.ColumnKey; ActiveRecordModel target = arCollection[model.HasManyAtt.MapType]; if ((table == null || keyColumn == null) && target == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find information about the specified target type {2}", model.Property.DeclaringType.Name, model.Property.Name, model.HasManyAtt.MapType)); } BelongsToModel targetBtModel = null; if (target != null) { foreach (BelongsToModel btModel in target.BelongsTo) { if (btModel.BelongsToAtt.Type == model.Property.DeclaringType || btModel.Property.PropertyType == model.Property.DeclaringType) { targetBtModel = btModel; break; } } } if ((table == null || keyColumn == null) && targetBtModel == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find a 'BelongsTo' mapped property in the target type {2}", model.Property.DeclaringType.Name, model.Property.Name, model.HasManyAtt.MapType)); } if (target != null) { VisitModel(target); } if (table == null) { table = target.ActiveRecordAtt.Table; } if (keyColumn == null) { keyColumn = targetBtModel.BelongsToAtt.Column; } model.HasManyAtt.Table = table; model.HasManyAtt.ColumnKey = keyColumn; }
/// <summary> /// Visits the has many. /// </summary> /// <remarks> /// Guess the type of the relation, if not specified explicitly /// Verify that the assoication is valid on [HasMany] /// Validate that required information is specified /// Infer the other side of the assoication and grab require data from it /// </remarks> /// <param name="model">The model.</param> public override void VisitHasMany(HasManyModel model) { if (model.HasManyAtt.MapType == null) { model.HasManyAtt.MapType = GuessType(null, model.Property.PropertyType); } model.HasManyAtt.RelationType = GuessRelation(model.Property, model.HasManyAtt.RelationType); // Guess the details about a map relation if needed if (model.HasManyAtt.RelationType == RelationType.Map) { if (string.IsNullOrEmpty(model.HasManyAtt.Table)) { model.HasManyAtt.Table = string.Format("{0}_{1}", model.Property.ReflectedType.Name, model.Property.Name); } if (model.HasManyAtt.IndexType == null) { model.HasManyAtt.IndexType = GetIndexTypeFromDictionary(model.Property.PropertyType).Name; } if (model.HasManyAtt.MapType == null) { model.HasManyAtt.MapType = GetMapTypeFromDictionary(model.Property.PropertyType); } } if (model.HasManyAtt.RelationType == RelationType.IdBag) { throw new ActiveRecordException(String.Format( "You can't use idbags in a many to one association (HasMany) {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } if (model.HasManyAtt.RelationType == RelationType.Map && model.HasManyAtt.Index == null) { throw new ActiveRecordException(String.Format( "A HasMany with type Map requires that you specify an 'Index', use the Index property {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } if (model.HasManyAtt.RelationType == RelationType.List && model.HasManyAtt.Index == null) { throw new ActiveRecordException(String.Format( "A HasMany with type List requires that you specify an 'Index', use the Index property {0}.{1} ", model.Property.DeclaringType.Name, model.Property.Name)); } // try to guess an <element> mapping if none of the mapping properties was set if (model.HasManyAtt.MapType.IsValueType && string.IsNullOrEmpty(model.HasManyAtt.Element) && model.HasManyAtt.ElementType == null && string.IsNullOrEmpty(model.HasManyAtt.ColumnKey)) { GuessElementMappingBasedOnEnum(model); } // Infer table and column based on possible belongs to // on the target class String table = model.HasManyAtt.Table; String keyColumn = model.HasManyAtt.ColumnKey; String[] compositeKeyColumnKeys = model.HasManyAtt.CompositeKeyColumnKeys; Type type = model.HasManyAtt.MapType; ActiveRecordModel target = arCollection[type]; if ((table == null || (keyColumn == null && compositeKeyColumnKeys == null)) && target == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find information about the specified target type {2}. If you have mapped a Collection or Dictionary of value types, please make sure you have specified the Table property.", model.Property.DeclaringType.Name, model.Property.Name, type)); } BelongsToModel targetBtModel = null; ActiveRecordModel tmpModel = target; while (tmpModel != null && targetBtModel == null) { foreach (BelongsToModel btModel in tmpModel.BelongsTo) { if (btModel.BelongsToAtt.Type != model.Property.DeclaringType && btModel.BelongsToAtt.Type != model.ContainingTypeModel.Type && btModel.Property.PropertyType != model.Property.DeclaringType && btModel.Property.PropertyType != model.ContainingTypeModel.Type) { continue; } targetBtModel = btModel; break; } tmpModel = tmpModel.Parent; } if ((table == null || (keyColumn == null && compositeKeyColumnKeys == null)) && targetBtModel == null) { throw new ActiveRecordException(String.Format( "ActiveRecord tried to infer details about the relation {0}.{1} but " + "it could not find a 'BelongsTo' mapped property in the target type {2}", model.Property.DeclaringType.Name, model.Property.Name, type)); } if (target != null) { VisitModel(target); } else if (model.HasManyAtt.DependentObjects) { VisitDependentObject(model.DependentObjectModel); } if (table == null) { table = target.ActiveRecordAtt.Table; } if (targetBtModel != null) { if (keyColumn == null && targetBtModel.BelongsToAtt.CompositeKeyColumns == null) { keyColumn = targetBtModel.BelongsToAtt.Column; } else { compositeKeyColumnKeys = targetBtModel.BelongsToAtt.CompositeKeyColumns; } } model.HasManyAtt.Table = table; if (keyColumn != null) { model.HasManyAtt.ColumnKey = keyColumn; } else { model.HasManyAtt.CompositeKeyColumnKeys = compositeKeyColumnKeys; } }