protected MetadataSchema GetMetadata() { if (_metadata == null) { lock (MetadataLock) { if (!FactoryMetadata.TryGetValue(Session.SessionFactory, out _metadata)) { var builder = new NHMetadataBuilder(Session.SessionFactory, _breezeConfig, _breezeConfigurator); _metadata = builder.BuildMetadata(TypeFilter); FactoryMetadata.Add(Session.SessionFactory, _metadata); OnMetadataBuilt(_metadata); } } } return(_metadata); }
/// <summary> /// Find out if a bidirectional relation exists, if exists then add entity to the collection /// </summary> /// <param name="manyToOneType">Many to one relation</param> /// <param name="childEntityType">Entity type of the child</param> /// <param name="propertyName">Property name of the ManyToOne realtion</param> /// <param name="childEntityInfo">Entity info of the child</param> /// <param name="childMeta">Child metadata</param> /// <returns>true if the child entity was added or removed from the parent entity collection, otherwise false</returns> private bool TryToFindAndLinkBidirectionalRelation(ManyToOneType manyToOneType, EntityType childEntityType, string propertyName, EntityInfo childEntityInfo, IClassMetadata childMeta) { var fk = FindForeignKey(propertyName, childMeta); var parentMeta = _session.SessionFactory.GetClassMetadata(manyToOneType.ReturnedClass); var propNames = parentMeta.PropertyNames; var propTypes = parentMeta.PropertyTypes; var childPersister = childMeta as AbstractEntityPersister; if (childPersister == null) { return(false); } var colProp = new Dictionary <string, string>(); for (var i = 0; i < childPersister.PropertyNames.Length; i++) { var propName = childPersister.PropertyNames[i]; var propType = childPersister.GetPropertyType(propName); if (propType.IsAssociationType) { continue; } foreach (var col in childPersister.GetPropertyColumnNames(i)) { if (col == null) { continue; // formula } if (!colProp.ContainsKey(col)) { colProp.Add(col, propName); } } } if (childPersister.IdentifierType.IsComponentType) { var componentType = (ComponentType)childPersister.IdentifierType; for (var i = 0; i < componentType.PropertyNames.Length; i++) { colProp.Add(childPersister.IdentifierColumnNames[i], componentType.PropertyNames[i]); } } else { foreach (var col in childPersister.IdentifierColumnNames) { colProp.Add(col, childPersister.IdentifierPropertyName); } } for (var i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; var propName = propNames[i]; if (!propType.IsAssociationType || !propType.IsCollectionType) { continue; } var colType = (CollectionType)propType; var refCols = colType.GetReferencedColumns(_session.GetSessionImplementation().Factory); var refProps = refCols.Select(refCol => !colProp.ContainsKey(refCol) ? refCol : colProp[refCol]).ToArray(); if (NHMetadataBuilder.CatColumnNames(refProps) != fk) { continue; } var elmType = colType.GetElementType(_session.GetSessionImplementation().Factory); if (!elmType.ReturnedClass.IsAssignableFrom(childMeta.MappedClass)) { continue; } var parentEntity = GetRelatedEntity(propertyName, childEntityType, childEntityInfo, childMeta); if (parentEntity == null) { return(false); } var coll = parentMeta.GetPropertyValue(parentEntity, propName) as IEnumerable; if (coll == null) //Should happen only if the parent entity is not in db { //TODO: instantiate collection continue; } var collType = coll.GetType(); //Initialize collection in order to prevent flushing if (!NHibernateUtil.IsInitialized(coll)) { NHibernateUtil.Initialize(coll); } if (colType.ReturnedClass.IsGenericType) { var state = childEntityInfo.EntityState; if (_saveMap.ContainsKey(manyToOneType.ReturnedClass)) { var parentEntityInfo = _saveMap[manyToOneType.ReturnedClass].FirstOrDefault(o => o.Entity == parentEntity); if (parentEntityInfo != null) { switch (parentEntityInfo.EntityState) { case EntityState.Added: //if the parent is added then we need to add child to the collection even if the it is only updated or unmodified if (state != EntityState.Deleted) { state = EntityState.Added; } break; case EntityState.Deleted: //TODO: check for cascade option break; case EntityState.Modified: break; } } } //TODO: check if parent is new switch (state) { case EntityState.Deleted: var removeMethod = collType.GetMethod("Remove") ?? collType.GetInterfaces() .Select(o => o.GetMethod("Remove")) .FirstOrDefault(o => o != null); var removed = false; if (removeMethod != null) { IEqualityComparer comparer = new EntityComparer(childMeta); foreach (var item in coll) { if (comparer.Equals(item, childEntityInfo.Entity)) { removed = (bool)removeMethod.Invoke(coll, new[] { item }); break; } } } childMeta.SetPropertyValue(childEntityInfo.Entity, propertyName, null); //Remove relation on both sides return(removed); case EntityState.Added: var addMethod = collType.GetMethod("Add") ?? collType.GetInterfaces() .Select(o => o.GetMethod("Add")) .FirstOrDefault(o => o != null); if (addMethod != null) { addMethod.Invoke(coll, new[] { childEntityInfo.Entity }); return(true); } break; } } //TODO: non generic collections } return(false); }