/// <summary> /// Adds the specified field. /// </summary> /// <param name="field">The field.</param> public void Add(IStorageField field) { if (List.ContainsKey(field.Id)) { this[field.Id] = field; } else { List.Add(field.Id, field); } }
public void ConvertNtoNRelations() { List <IStorageEntityRelation> relations = Read(); foreach (var relation in relations) { if (relation.RelationType != Api.Models.EntityRelationType.ManyToMany) { continue; } MongoEntity originEntity = MongoStaticContext.Context.Entities.GetById(relation.OriginEntityId); MongoEntity targetEntity = MongoStaticContext.Context.Entities.GetById(relation.TargetEntityId); IStorageField originField = originEntity.Fields.SingleOrDefault(x => x.Id == relation.OriginFieldId); IStorageField targetField = targetEntity.Fields.SingleOrDefault(x => x.Id == relation.TargetFieldId); string originRelationFieldName = $"#{relation.Name}_origins"; string targetRelationFieldName = $"#{relation.Name}_targets"; var relationEntityRecordCollections = MongoStaticContext.Context.GetBsonCollection(RELATION_COLLECTION_PREFIX + relation.Name); var relationEntityRecords = relationEntityRecordCollections.FindAll().ToList(); if (relationEntityRecords != null && relationEntityRecords.Count() > 0) { var transaction = MongoStaticContext.Context.CreateTransaction(); try { var originEntityRecordCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + originEntity.Name); var originEntityRecords = originEntityRecordCollection.FindAll().ToList(); if (originEntityRecords != null && originEntityRecords.Count() > 0) { foreach (var originRecord in originEntityRecords) { string originFieldName = originField.Name == "id" ? $"_id" : originField.Name; List <Guid> targetRecordsToCopy = relationEntityRecords.Where(r => (Guid)r["originId"] == (Guid)originRecord[originFieldName]).Select(r => (Guid)r["targetId"]).ToList(); originRecord[targetRelationFieldName] = targetRecordsToCopy == null || targetRecordsToCopy.Count() == 0 ? BsonNull.Value : BsonValue.Create(targetRecordsToCopy); var updateSuccess = originEntityRecordCollection.Save(originRecord).DocumentsAffected > 0; //if (!updateSuccess) // throw new StorageException("Failed to update record."); } } var targetEntityRecordCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + targetEntity.Name); var targetEntityRecords = targetEntityRecordCollection.FindAll().ToList(); if (targetEntityRecords != null && targetEntityRecords.Count() > 0) { foreach (var targetRecord in targetEntityRecords) { string targetFieldName = targetField.Name == "id" ? $"_id" : targetField.Name; List <Guid> originRecordsToCopy = relationEntityRecords.Where(r => (Guid)r["targetId"] == (Guid)targetRecord[targetFieldName]).Select(r => (Guid)r["originId"]).ToList(); targetRecord[originRelationFieldName] = originRecordsToCopy == null || originRecordsToCopy.Count() == 0 ? BsonNull.Value : BsonValue.Create(originRecordsToCopy);; var updateSuccess = targetEntityRecordCollection.Save(targetRecord).DocumentsAffected > 0; //if (!updateSuccess) // throw new StorageException("Failed to update record."); } } transaction.Commit(); IndexOptionsBuilder originOptions = IndexOptions.SetUnique(false).SetDropDups(false).SetName(targetRelationFieldName).SetBackground(true); originEntityRecordCollection.CreateIndex(new IndexKeysBuilder().Ascending(targetRelationFieldName), originOptions); IndexOptionsBuilder targetOptions = IndexOptions.SetUnique(false).SetDropDups(false).SetName(originRelationFieldName).SetBackground(true); targetEntityRecordCollection.CreateIndex(new IndexKeysBuilder().Ascending(originRelationFieldName), targetOptions); } catch (Exception) { transaction.Rollback(); } } } }
private void InvalidateRelationIndex(IStorageEntityRelation entityRelation, bool dropIndexes = false) { var entityRepository = new MongoEntityRepository(); var originEntity = entityRepository.Read(entityRelation.OriginEntityId); var targetEntity = entityRepository.Read(entityRelation.TargetEntityId); if (originEntity == null || targetEntity == null) { return; } IStorageField originField = originEntity.Fields.SingleOrDefault(x => x.Id == entityRelation.OriginFieldId); IStorageField targetField = targetEntity.Fields.SingleOrDefault(x => x.Id == entityRelation.TargetFieldId); if (originField == null || targetField == null) { return; } if (entityRelation.RelationType != Api.Models.EntityRelationType.ManyToMany) { var originCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + originEntity.Name); if (originCollection == null) { return; } if (originField.Name != "id") { var originIndexes = originCollection.GetIndexes(); var originIndexName = "relation_" + entityRelation.Name + "_" + originField.Name; var originIndex = originIndexes.SingleOrDefault(x => x.Name == originIndexName); if (originIndex != null) { originCollection.DropIndexByName(originIndexName); } if (!dropIndexes) { IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(originIndexName).SetBackground(true); originCollection.CreateIndex(new IndexKeysBuilder().Ascending(originField.Name), options); } } var targetCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + targetEntity.Name); if (targetEntity == null) { return; } if (targetField.Name != "id") { var targetIndexes = targetCollection.GetIndexes(); var targetIndexName = "relation_" + entityRelation.Name + "_" + targetField.Name; var targetIndex = targetIndexes.SingleOrDefault(x => x.Name == targetIndexName); if (targetIndex != null) { targetCollection.DropIndexByName(targetIndexName); } if (!dropIndexes) { IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(targetIndexName).SetBackground(true); targetCollection.CreateIndex(new IndexKeysBuilder().Ascending(targetField.Name), options); } } } else { //at the moment many to many relation do not need any endexes /* * var originCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + originEntity.Name); * if (originCollection == null) * return; * * var originIndexes = originCollection.GetIndexes(); * var originIndexName = "relation_" + entityRelation.Name + "_targets"; * var originIndex = originIndexes.SingleOrDefault(x => x.Name == originIndexName); * if (originIndex != null) * originCollection.DropIndexByName(originIndexName); * * if (!dropIndexes) * { * var originFieldName = $"#" + entityRelation.Name + "_targets"; * IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(originIndexName).SetBackground(true); * originCollection.CreateIndex(new IndexKeysBuilder().Ascending(originFieldName), options); * } * * var targetCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + targetEntity.Name); * if (targetEntity == null) * return; * * var targetIndexes = targetCollection.GetIndexes(); * var targetIndexName = "relation_" + entityRelation.Name + "_origins"; * var targetIndex = targetIndexes.SingleOrDefault(x => x.Name == targetIndexName); * if (targetIndex != null) * targetCollection.DropIndexByName(targetIndexName); * * if (!dropIndexes) * { * var targetFieldName = $"#" + entityRelation.Name + "_origins"; * IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(targetIndexName).SetBackground(true); * targetCollection.CreateIndex(new IndexKeysBuilder().Ascending(targetFieldName), options); * } */ } }
private List <ErrorModel> ValidateRelation(EntityRelation relation, ValidationType validationType) { List <ErrorModel> errors = new List <ErrorModel>(); if (validationType == ValidationType.Update) { //we cannot update relation with missing Id (Guid.Empty means id is missing) //of if there is no relation with this id already if (relation.Id == Guid.Empty) { errors.Add(new ErrorModel("id", null, "Id is required!")); } else if (relationRepository.Read(relation.Id) == null) { errors.Add(new ErrorModel("id", relation.Id.ToString(), "Entity relation with such Id does not exist!")); } } else if (validationType == ValidationType.Create) { //if id is null, them we later will assing one before create process //otherwise check if relation with same id already exists if (relation.Id != Guid.Empty && (relationRepository.Read(relation.Id) != null)) { errors.Add(new ErrorModel("id", relation.Id.ToString(), "Entity relation with such Id already exist!")); } } else if (validationType == ValidationType.RelationsOnly) { //no need to check anything, we need to check only Entities and Fields relations //this case is here only for readability } IStorageEntityRelation existingRelation = null; if (validationType == ValidationType.Create || validationType == ValidationType.Update) { //validate name // - if name string is correct // - then if relation with same name already exists var nameValidationErrors = ValidationUtility.ValidateName(relation.Name); if (nameValidationErrors.Count > 0) { errors.AddRange(nameValidationErrors); } else { existingRelation = relationRepository.Read(relation.Name); if (validationType == ValidationType.Create) { //if relation with same name alfready exists if (existingRelation != null) { errors.Add(new ErrorModel("name", relation.Name, string.Format("Entity relation '{0}' exists already!", relation.Name))); } } else if (validationType == ValidationType.Update) { //if relation with same name alfready and different Id already exists if (existingRelation != null && existingRelation.Id != relation.Id) { errors.Add(new ErrorModel("name", relation.Name, string.Format("Entity relation '{0}' exists already!", relation.Name))); } } } } else if (validationType == ValidationType.RelationsOnly) { //no need to check anything, we need to check only Entities and Fields relations //this case is here only for readability } errors.AddRange(ValidationUtility.ValidateLabel(relation.Label)); IStorageEntity originEntity = entityRepository.Read(relation.OriginEntityId); IStorageEntity targetEntity = entityRepository.Read(relation.TargetEntityId); IStorageField originField = null; IStorageField targetField = null; if (originEntity == null) { errors.Add(new ErrorModel("originEntity", relation.OriginEntityId.ToString(), "The origin entity do not exist.")); } else { originField = originEntity.Fields.SingleOrDefault(x => x.Id == relation.OriginFieldId); if (originField == null) { errors.Add(new ErrorModel("originField", relation.OriginFieldId.ToString(), "The origin field do not exist.")); } if (!(originField is IStorageGuidField)) { errors.Add(new ErrorModel("originField", relation.OriginFieldId.ToString(), "The origin field should be Unique Identifier (GUID) field.")); } } if (targetEntity == null) { errors.Add(new ErrorModel("targetEntity", relation.TargetEntityId.ToString(), "The target entity do not exist.")); } else { targetField = targetEntity.Fields.SingleOrDefault(x => x.Id == relation.TargetFieldId); if (targetField == null) { errors.Add(new ErrorModel("targetField", relation.TargetFieldId.ToString(), "The target field do not exist.")); } if (!(targetField is IStorageGuidField)) { errors.Add(new ErrorModel("targetField", relation.TargetFieldId.ToString(), "The target field should be Unique Identifier (GUID) field.")); } } //the second level validation requires no errors on first one //so if there are errors in first level we return them if (errors.Count > 0) { return(errors); } if (validationType == ValidationType.Update) { if (existingRelation.RelationType != relation.RelationType) { errors.Add(new ErrorModel("relationType", relation.RelationType.ToString(), "The initialy selected relation type is readonly and cannot be changed.")); } if (existingRelation.OriginEntityId != relation.OriginEntityId) { errors.Add(new ErrorModel("originEntityId", relation.OriginEntityId.ToString(), "The origin entity differ from initial one. The initialy selected origin entity is readonly and cannot be changed.")); } if (existingRelation.OriginFieldId != relation.OriginFieldId) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field differ from initial one. The initialy selected origin field is readonly and cannot be changed.")); } if (existingRelation.TargetEntityId != relation.TargetEntityId) { errors.Add(new ErrorModel("targetEntityId", relation.TargetEntityId.ToString(), "The target entity differ from initial one. The initialy selected target entity is readonly and cannot be changed.")); } if (existingRelation.TargetFieldId != relation.TargetFieldId) { errors.Add(new ErrorModel("TargetFieldId", relation.TargetFieldId.ToString(), "The target field differ from initial one. The initialy selected target field is readonly and cannot be changed.")); } } else if (validationType == ValidationType.Create) { if (relation.RelationType == EntityRelationType.OneToMany || relation.RelationType == EntityRelationType.OneToOne) { //validate if target and origin field is same field for following relations if (relation.OriginEntityId == relation.TargetEntityId && relation.OriginFieldId == relation.TargetFieldId) { errors.Add(new ErrorModel("", "", "The origin and target fields cannot be the same.")); } //validate there is no other already existing relation with same parameters foreach (var rel in relationRepository.Read()) { if (rel.OriginEntityId == relation.OriginEntityId && rel.TargetEntityId == relation.TargetEntityId && rel.OriginFieldId == relation.OriginFieldId && rel.TargetFieldId == relation.TargetFieldId) { errors.Add(new ErrorModel("", "", "There is already existing relation with same parameters.")); } } } if (relation.RelationType == EntityRelationType.OneToOne || relation.RelationType == EntityRelationType.ManyToMany) { if (!originField.Required) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Required")); } if (!originField.Unique) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Unique")); } if (!targetField.Required) { errors.Add(new ErrorModel("targetFieldId", relation.TargetFieldId.ToString(), "The target field must be specified as Required")); } if (!targetField.Unique) { errors.Add(new ErrorModel("targetFieldId", relation.TargetFieldId.ToString(), "The target field must be specified as Unique")); } } if (relation.RelationType == EntityRelationType.OneToMany) { if (!originField.Required) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Required")); } if (!originField.Unique) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Unique")); } } } if (validationType == ValidationType.RelationsOnly) { if (relation.RelationType == EntityRelationType.OneToOne || relation.RelationType == EntityRelationType.ManyToMany) { if (!originField.Required) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Required")); } if (!originField.Unique) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Unique")); } if (!targetField.Required) { errors.Add(new ErrorModel("targetFieldId", relation.TargetFieldId.ToString(), "The target field must be specified as Required")); } if (!targetField.Unique) { errors.Add(new ErrorModel("targetFieldId", relation.TargetFieldId.ToString(), "The target field must be specified as Unique")); } } if (relation.RelationType == EntityRelationType.OneToMany) { if (!originField.Required) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Required")); } if (!originField.Unique) { errors.Add(new ErrorModel("originFieldId", relation.OriginFieldId.ToString(), "The origin field must be specified as Unique")); } } } return(errors); }
private void InvalidateRelationIndex(IStorageEntityRelation entityRelation) { MongoEntity originEntity = MongoStaticContext.Context.Entities.GetById(entityRelation.OriginEntityId); MongoEntity targetEntity = MongoStaticContext.Context.Entities.GetById(entityRelation.TargetEntityId); if (originEntity == null || targetEntity == null) { return; } IStorageField originField = originEntity.Fields.SingleOrDefault(x => x.Id == entityRelation.OriginFieldId); IStorageField targetField = targetEntity.Fields.SingleOrDefault(x => x.Id == entityRelation.TargetFieldId); if (originField == null || targetField == null) { return; } if (entityRelation.RelationType != Api.Models.EntityRelationType.ManyToMany) { var originCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + originEntity.Name); if (originCollection == null) { return; } if (originField.Name != "id") { var originIndexes = originCollection.GetIndexes(); var originIndexName = "relation_" + entityRelation.Id + "_" + originField.Name; var originIndex = originIndexes.SingleOrDefault(x => x.Name == originIndexName); if (originIndex != null) { originCollection.DropIndexByName(originIndexName); } IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(originIndexName).SetBackground(true); originCollection.CreateIndex(new IndexKeysBuilder().Ascending(originField.Name), options); } var targetCollection = MongoStaticContext.Context.GetBsonCollection(MongoRecordRepository.RECORD_COLLECTION_PREFIX + targetEntity.Name); if (targetEntity == null) { return; } if (targetField.Name != "id") { var targetIndexes = targetCollection.GetIndexes(); var targetIndexName = "relation_" + entityRelation.Id + "_" + targetField.Name; var targetIndex = targetIndexes.SingleOrDefault(x => x.Name == targetIndexName); if (targetIndex != null) { targetCollection.DropIndexByName(targetIndexName); } IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(targetIndexName).SetBackground(true); targetCollection.CreateIndex(new IndexKeysBuilder().Ascending(targetField.Name), options); } } else { var collection = MongoStaticContext.Context.GetBsonCollection(RELATION_COLLECTION_PREFIX + entityRelation.Name); var indexes = collection.GetIndexes(); var originIndexName = "relation_origin"; var originIndex = indexes.SingleOrDefault(x => x.Name == originIndexName); if (originIndex != null) { collection.DropIndexByName(originIndexName); } IndexOptionsBuilder options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(originIndexName).SetBackground(true); collection.CreateIndex(new IndexKeysBuilder().Ascending("relationId").Ascending("originId"), options); var targetIndexName = "relation_target"; var targetIndex = indexes.SingleOrDefault(x => x.Name == targetIndexName); if (targetIndex != null) { collection.DropIndexByName(targetIndexName); } options = IndexOptions.SetUnique(false).SetDropDups(false).SetName(targetIndexName).SetBackground(true); collection.CreateIndex(new IndexKeysBuilder().Ascending("relationId").Ascending("targetId"), options); } }