/// <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);
                 * }
                 */
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
            }
        }