Ejemplo n.º 1
0
        /// <summary>
        /// Make association property metadata for the entity.
        /// Also populates the ForeignKeyMap which is used for related-entity fixup in NHContext.FixupRelationships
        /// </summary>
        /// <param name="containingPersister">Entity Persister containing the property</param>
        /// <param name="propType">Association property</param>
        /// <param name="propName">Name of the property</param>
        /// <param name="dataProperties">Data properties already collected for the containingType.  "isPartOfKey" may be added to a property.</param>
        /// <param name="isKey">Whether the property is part of the key</param>
        /// <returns></returns>
        private Dictionary <string, object> MakeAssociationProperty(AbstractEntityPersister containingPersister, IAssociationType propType, string propName, List <Dictionary <string, object> > dataProperties, bool isKey)
        {
            var nmap = new Dictionary <string, object>();

            nmap.Add("nameOnServer", propName);

            var relatedEntityType = GetEntityType(propType.ReturnedClass, propType.IsCollectionType);

            nmap.Add("entityTypeName", relatedEntityType.Name + ":#" + relatedEntityType.Namespace);
            nmap.Add("isScalar", !propType.IsCollectionType);

            // the associationName must be the same at both ends of the association.
            var containingType = containingPersister.EntityMetamodel.Type;
            var columnNames    = GetPropertyColumnNames(containingPersister, propName, propType);

            var relatedEntityTypeName = relatedEntityType.Name;

            var propertyType = relatedEntityType.GetProperty(propName, BindingFlags.Instance | BindingFlags.Public);

            if (propertyType?.DeclaringType != null)
            {
                var declaringTypeMetadata = _sessionFactory.GetClassMetadata(propertyType.DeclaringType) as SingleTableEntityPersister;

                if (declaringTypeMetadata != null && declaringTypeMetadata.DiscriminatorValue != null)
                {
                    relatedEntityTypeName = declaringTypeMetadata.EntityName.Split('.').Last();
                }
            }

            nmap.Add("associationName", GetAssociationName(containingType.Name, relatedEntityTypeName, columnNames));

            if (_breezeConfig.HasOrphanDeleteEnabled)
            {
                var propertyIndex = containingPersister.PropertyNames.ToList().IndexOf(propName);
                var cascadeStyle  = containingPersister.PropertyCascadeStyles[propertyIndex];
                nmap.Add("hasOrphanDelete", cascadeStyle.HasOrphanDelete);
            }


            string[] fkNames             = null;
            var      joinable            = propType.GetAssociatedJoinable((ISessionFactoryImplementor)this._sessionFactory);
            var      memberConfiguration = GetMemberConfiguration(containingType, propName);

            if (!string.IsNullOrEmpty(memberConfiguration.SerializedName))
            {
                nmap.Add("name", memberConfiguration.SerializedName);
            }

            if (propType.IsCollectionType)
            {
                // inverse foreign key
                var collectionPersister = joinable as AbstractCollectionPersister;
                if (collectionPersister != null)
                {
                    // many-to-many relationships do not have a direct connection on the client or in metadata
                    var elementPersister = collectionPersister.ElementPersister as AbstractEntityPersister;
                    if (elementPersister != null)
                    {
                        fkNames = GetPropertyNamesForColumns(elementPersister, columnNames);
                        if (fkNames != null)
                        {
                            nmap.Add("invForeignKeyNamesOnServer", fkNames);
                        }
                    }
                }
            }
            else
            {
                // Not a collection type - a many-to-one or one-to-one association
                var entityRelationship = containingType.FullName + '.' + propName;
                // Look up the related foreign key name using the column name
                fkNames = GetPropertyNamesForColumns(containingPersister, columnNames);

                // TODO: support FK with multiple columns
                if (fkNames == null && columnNames.Length == 1) //try to find the column for the relation if is not specified in class
                {
                    var pType = containingPersister.GetPropertyType(propName);
                    var index = containingPersister.PropertyNames
                                .Select((val, i) => new { Index = i, Value = val })
                                .Where(o => o.Value == propName)
                                .Select(o => o.Index)
                                .First();
                    var isNullable       = containingPersister.PropertyNullability[index];
                    var convertedColumns = new List <string>();
                    foreach (var columnName in columnNames)
                    {
                        var synProp = new NHSyntheticProperty
                        {
                            Name           = columnName.ToPascalCase(),
                            FkPropertyName = propName,
                            FkType         = pType,
                            IsNullable     = isNullable
                        };
                        convertedColumns.Add(columnName.ToPascalCase());

                        var relatedType = _sessionFactory.GetClassMetadata(synProp.FkType.Name);
                        if (relatedType == null)
                        {
                            throw new ArgumentException("Could not find related entity of type " + synProp.FkType.Name);
                        }
                        synProp.PkType         = relatedType.IdentifierType;
                        synProp.PkPropertyName = relatedType.IdentifierPropertyName;

                        if (!_syntheticProperties.ContainsKey(containingType))
                        {
                            _syntheticProperties.Add(containingType, new List <NHSyntheticProperty>());
                        }
                        _syntheticProperties[containingType].Add(synProp);

                        //Create synthetic property as unmapped
                        var dmap = MakeDataProperty(memberConfiguration, columnName.ToPascalCase(), relatedType.IdentifierType, synProp.IsNullable, false, false);
                        dmap["isUnmapped"] = true;
                        dataProperties.Add(dmap);
                    }
                    fkNames = convertedColumns.ToArray();
                }


                if (fkNames != null)
                {
                    if (propType.ForeignKeyDirection == ForeignKeyDirection.ForeignKeyFromParent)
                    {
                        nmap.Add("foreignKeyNamesOnServer", fkNames);
                    }
                    else
                    {
                        nmap.Add("invForeignKeyNamesOnServer", fkNames);
                    }

                    // For many-to-one and one-to-one associations, save the relationship in ForeignKeyMap for re-establishing relationships during save
                    _map.ForeignKeyMap.Add(entityRelationship, string.Join(",", fkNames));
                    if (isKey)
                    {
                        foreach (var fkName in fkNames)
                        {
                            var relatedDataProperty = FindPropertyByName(dataProperties, fkName);
                            if (!relatedDataProperty.ContainsKey("isPartOfKey"))
                            {
                                relatedDataProperty.Add("isPartOfKey", true);
                            }
                        }
                    }
                }
                else if (fkNames == null)
                {
                    nmap.Add("foreignKeyNamesOnServer", columnNames);
                    nmap.Add("ERROR", "Could not find matching fk for property " + entityRelationship);
                    _map.ForeignKeyMap.Add(entityRelationship, string.Join(",", columnNames));
                    throw new ArgumentException("Could not find matching fk for property " + entityRelationship);
                }
            }

            return(nmap);
        }
Ejemplo n.º 2
0
 public NHSyntheticPropertyValueProvider(NHSyntheticProperty syntheticProp)
 {
     _syntheticProp = syntheticProp;
 }