/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) { // entities are already connected - still need to add to dependency graph EntityInfo relatedEntityInfo = FindInSaveMapByEntity(propType.ReturnedClass, relatedEntity); MaybeAddToGraph(entityInfo, relatedEntityInfo, propType); return; } relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) { meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); } }
protected override int ExecuteInsert(IDictionary values) { ActiveRecordDataSourceCreateEventArgs args = new ActiveRecordDataSourceCreateEventArgs(); args.ModelType = BuildManager.GetType(Source.TypeName, false, true); args.CreateValues = values; CreateValuesFromCreateParameters(args); IClassMetadata meta = ActiveRecordMediator.GetSessionFactoryHolder().GetSessionFactory(args.ModelType).GetClassMetadata(args.ModelType); if (!meta.HasIdentifierProperty) { throw new ApplicationException("ActiveRecordDataSourceView requires a primary key for the update method."); } Source.OnBeforeCreate(args); if (args.Cancel) { return(0); } try { if (args.Entity == null) { args.Entity = Activator.CreateInstance(args.ModelType); } foreach (string key in args.CreateValues.Keys) { meta.SetPropertyValue(args.Entity, key, args.CreateValues[key]); } ActiveRecordMediator.Create(args.Entity); } catch (Exception e) { args.Exception = e; args.WasError = true; Source.OnCreateError(args); if (Source.ThrowOnError && !args.DoNotThrow) { throw; } return(0); } Source.OnCreate(args); return(1); }
private bool SetupEntityInfoForSerialization(Type entityType, EntityInfo entityInfo, IClassMetadata meta) { if (!_removeMode || !_clientEntityObjects.ContainsKey(entityInfo)) { return(false); } var clientEntity = _clientEntityObjects[entityInfo]; var id = meta.GetIdentifier(entityInfo.Entity); meta.SetIdentifier(clientEntity, id); //We have to set the properties from the client object var propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; for (var i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; var propName = propNames[i]; if (propType.IsAssociationType) { continue; } if (propType.IsComponentType) { var compType = (ComponentType)propType; var compPropNames = compType.PropertyNames; var compPropTypes = compType.Subtypes; var component = GetPropertyValue(meta, entityInfo.Entity, propName); var compValues = compType.GetPropertyValues(component); for (var j = 0; j < compPropNames.Length; j++) { var compPropType = compPropTypes[j]; if (!compPropType.IsAssociationType) { continue; } compValues[j] = null; } var clientCompVal = GetPropertyValue(meta, clientEntity, propName); compType.SetPropertyValues(clientCompVal, compValues); } else { var val = meta.GetPropertyValue(entityInfo.Entity, propName); meta.SetPropertyValue(clientEntity, propName, val); } } // TODO: update unmapped properties typeof(EntityInfo).GetProperty("Entity").SetValue(entityInfo, clientEntity); return(true); }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) { return; // entities are already connected } relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) { meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); } }
/// <summary> /// Restore the old value of the concurrency column so Hibernate will save the entity. /// Otherwise it will complain because Breeze has already changed the value. /// </summary> /// <param name="entityInfo"></param> /// <param name="classMeta"></param> private void RestoreOldVersionValue(EntityInfo entityInfo, IClassMetadata classMeta) { var vcol = classMeta.VersionProperty; var vname = classMeta.PropertyNames[vcol]; object oldVersion; if (entityInfo.OriginalValuesMap.TryGetValue(vname, out oldVersion)) { var entity = entityInfo.Entity; var vtype = classMeta.PropertyTypes[vcol].ReturnedClass; oldVersion = Convert.ChangeType(oldVersion, vtype); // because JsonConvert makes all integers Int64 classMeta.SetPropertyValue(entity, vname, oldVersion, EntityMode.Poco); } }
/// <summary> /// Set the navigation properties to null on the given entity. /// </summary> /// <param name="entityInfo"></param> /// <param name="meta"></param> private void RemoveRelationships(EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; var propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; for (int i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; if (propType.IsAssociationType && propType.IsEntityType) { meta.SetPropertyValue(entity, propNames[i], null, EntityMode.Poco); } } }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (_removeMode) { var foreignKeyName = FindForeignKey(propName, meta); var id = GetForeignKeyValue(entityInfo, meta, foreignKeyName); meta.SetPropertyValue(entity, propName, null); if (id != null) { meta.SetPropertyValue(entity, foreignKeyName, id); //Set the foreigenkey as the foreign key property may be computed (resets when the relation is set) } return; } //object relatedEntity = GetPropertyValue(meta, entity, propName); //if (relatedEntity != null) return; // entities are already connected var relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); //if (relatedEntity != null) Unset if the synthetic property is not set meta.SetPropertyValue(entity, propName, relatedEntity); }
/// <summary> /// Sets the value. /// </summary> /// <param name="targetResource">The target resource.</param> /// <param name="propertyName">Name of the property.</param> /// <param name="propertyValue">The property value.</param> void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue) { IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName); if (metadata == null) { throw new DataServiceException("Type not recognized as a valid type for this Context"); } // See if its the Key property first if (metadata.IdentifierPropertyName == propertyName) { metadata.SetIdentifier(targetResource, propertyValue, EntityMode.Poco); } else // Else set the property { metadata.SetPropertyValue(targetResource, propertyName, propertyValue, EntityMode.Poco); } }
/// <summary> /// Connect the related entities based on the foreign key values. /// Note that this may cause related entities to be loaded from the DB if they are not already in the session. /// </summary> /// <param name="entityInfo">Entity that will be saved</param> /// <param name="meta">Metadata about the entity type</param> private void FixupRelationships(EntityInfo entityInfo, IClassMetadata meta) { var propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; if (meta.IdentifierType != null) { var propType = meta.IdentifierType; if (propType.IsAssociationType && propType.IsEntityType) { FixupRelationship(meta.IdentifierPropertyName, (EntityType)propType, entityInfo, meta); } else if (propType.IsComponentType) { FixupComponentRelationships(meta.IdentifierPropertyName, (ComponentType)propType, entityInfo, meta); } } for (var i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; if (propType.IsAssociationType && propType.IsEntityType) { FixupRelationship(propNames[i], (EntityType)propTypes[i], entityInfo, meta); var oneToManyType = propType as ManyToOneType; if (oneToManyType != null && !_removeMode) { TryToFindAndLinkBidirectionalRelation(oneToManyType, (EntityType)propTypes[i], propNames[i], entityInfo, meta); } } else if (propType.IsComponentType) { FixupComponentRelationships(propNames[i], (ComponentType)propType, entityInfo, meta); } else if (propType.IsAssociationType && propType.IsCollectionType && _removeMode) { meta.SetPropertyValue(entityInfo.Entity, propNames[i], null); } } }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) return; // entities are already connected relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
/// <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); }
private bool SetupEntityInfoForSaving(Type entityType, EntityInfo entityInfo, IClassMetadata meta) { var id = meta.GetIdentifier(entityInfo.Entity); var sessionImpl = _session.GetSessionImplementation(); object dbEntity; string[] propNames; if (entityInfo.EntityState == EntityState.Added) { //meta.Instantiate(id) -> Instantiate method can create a proxy when formulas are present. Saving non persistent proxies will throw an exception dbEntity = Activator.CreateInstance(entityType, true); meta.SetIdentifier(dbEntity, id); } else { //dbEntity = session.Get(entityType, id); Get is not good as it can return a proxy if (meta.IdentifierType.IsComponentType) { // for entities with composite key the identifier is the entity itself // we need to create a copy as ImmediateLoad will fill the given entity var componentType = (ComponentType)meta.IdentifierType; dbEntity = Activator.CreateInstance(entityType, true); // We need to check if the primary key was changed var oldKeyValues = new object[componentType.PropertyNames.Length]; var keyModified = false; for (var i = 0; i < componentType.PropertyNames.Length; i++) { var propName = componentType.PropertyNames[i]; if (entityInfo.OriginalValuesMap.ContainsKey(propName)) { oldKeyValues[i] = entityInfo.OriginalValuesMap[propName]; keyModified = true; } else { oldKeyValues[i] = componentType.GetPropertyValue(entityInfo.Entity, i); } } componentType.SetPropertyValues(dbEntity, oldKeyValues); dbEntity = sessionImpl.ImmediateLoad(entityType.FullName, dbEntity); // As NHibernate does not support updating the primary key we need to do it manually using hql if (keyModified) { var newKeyValues = componentType.GetPropertyValues(entityInfo.Entity); var parameters = new Dictionary <string, KeyValuePair <object, IType> >(); var setStatement = "set "; var whereStatement = "where "; for (var i = 0; i < componentType.PropertyNames.Length; i++) { if (i > 0) { setStatement += ", "; whereStatement += " and "; } var propName = componentType.PropertyNames[i]; var paramName = string.Format("new{0}", propName); setStatement += string.Format("{0}=:{1}", propName, paramName); parameters.Add(paramName, new KeyValuePair <object, IType>(newKeyValues[i], componentType.Subtypes[i])); paramName = string.Format("old{0}", propName); whereStatement += string.Format("{0}=:{1}", propName, paramName); parameters.Add(paramName, new KeyValuePair <object, IType>(oldKeyValues[i], componentType.Subtypes[i])); } var updateQuery = sessionImpl.CreateQuery(new StringQueryExpression(string.Format("update {0} {1} {2}", entityType.Name, setStatement, whereStatement))); foreach (var pair in parameters) { updateQuery.SetParameter(pair.Key, pair.Value.Key, pair.Value.Value); } var count = updateQuery.ExecuteUpdate(); if (count != 1) { throw new InvalidOperationException(string.Format("Query for updating composite key updated '{0}' rows instead of '1'", count)); } componentType.SetPropertyValues(dbEntity, componentType.GetPropertyValues(entityInfo.Entity)); } } else { dbEntity = sessionImpl.ImmediateLoad(entityType.FullName, id); } //dbEntity = session.Get(entityType, id, LockMode.None); } if (dbEntity == null) { throw new NullReferenceException(string.Format("Entity of type '{0}' with id '{1}' does not exists in database", entityType.FullName, id)); } //var modelConfig = BreezeModelConfigurator.GetModelConfiguration(entityType); //Save the original client object _clientEntityObjects[entityInfo] = entityInfo.Entity; //We have to set the properties from the client object propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; var config = _breezeConfigurator.GetModelConfiguration(entityType); // TODO: set only modified properties for (var i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; var propName = propNames[i]; var memberConfig = config.MemberConfigurations.ContainsKey(propName) ? config.MemberConfigurations[propName] : null; if (memberConfig != null && ( (memberConfig.Ignored.HasValue && memberConfig.Ignored.Value) || (memberConfig.Writable.HasValue && !memberConfig.Writable.Value) || (memberConfig.ShouldDeserializePredicate != null && memberConfig.ShouldDeserializePredicate.Invoke(entityInfo.Entity) == false) )) { continue; } if (propType.IsAssociationType) { continue; } if (propType.IsComponentType) { var compType = (ComponentType)propType; var componentVal = GetPropertyValue(meta, entityInfo.Entity, propName); var dbComponentVal = GetPropertyValue(meta, dbEntity, propName); var compPropsVal = compType.GetPropertyValues(componentVal); compType.SetPropertyValues(dbComponentVal, compPropsVal); } else { var val = meta.GetPropertyValue(entityInfo.Entity, propName); meta.SetPropertyValue(dbEntity, propName, val); } } typeof(EntityInfo).GetProperty("Entity").SetValue(entityInfo, dbEntity); return(true); }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) { // entities are already connected - still need to add to dependency graph EntityInfo relatedEntityInfo = FindInSaveMapByEntity(propType.ReturnedClass, relatedEntity); MaybeAddToGraph(entityInfo, relatedEntityInfo, propType); return; } relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
private bool SetupEntityInfoForSerialization(Type entityType, EntityInfo entityInfo, IClassMetadata meta) { if (!_removeMode || !_clientEntityObjects.ContainsKey(entityInfo)) { return(false); } var clientEntity = _clientEntityObjects[entityInfo]; var id = meta.GetIdentifier(entityInfo.Entity); meta.SetIdentifier(clientEntity, id); //We have to set the properties from the client object var propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; using (var childSession = _session.SessionWithOptions().Connection().OpenSession()) { for (var i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; var propName = propNames[i]; if (propType is IAssociationType associationType) { if (entityInfo.UnmappedValuesMap != null && new[] { "Id", "Code" }.Any(x => entityInfo.UnmappedValuesMap.ContainsKey(propName + x))) { var associatedEntityName = associationType.GetAssociatedEntityName((ISessionFactoryImplementor)_session.SessionFactory); var associatedEntityMetadata = _session.SessionFactory.GetClassMetadata(associatedEntityName); var associatedEntityValue = GetPropertyValue(meta, entityInfo.Entity, propName); if (associatedEntityValue != null) { clientEntity.SetMemberValue(propName, childSession.Load(associatedEntityName, GetPropertyValue(associatedEntityMetadata, associatedEntityValue, null))); } } } else if (propType.IsComponentType) { var compType = (ComponentType)propType; var compPropNames = compType.PropertyNames; var compPropTypes = compType.Subtypes; var component = GetPropertyValue(meta, entityInfo.Entity, propName); var compValues = compType.GetPropertyValues(component); for (var j = 0; j < compPropNames.Length; j++) { var compPropType = compPropTypes[j]; if (!compPropType.IsAssociationType) { continue; } compValues[j] = null; } var clientCompVal = GetPropertyValue(meta, clientEntity, propName); compType.SetPropertyValues(clientCompVal, compValues); } else { var val = meta.GetPropertyValue(entityInfo.Entity, propName); meta.SetPropertyValue(clientEntity, propName, val); } } } // TODO: update unmapped properties typeof(EntityInfo).GetProperty("Entity").SetValue(entityInfo, clientEntity); return(true); }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <param name="canUseSession">Whether we can load the related entity via the Session. /// If false, we only connect entities that are also in the saveMap</param> private void FixupRelationship(string propName, IType propType, EntityInfo entityInfo, IClassMetadata meta, bool canUseSession) { var entity = entityInfo.Entity; object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) return; // entities are already connected relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta, canUseSession); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }