internal protected int Execute(InsertCommand <T> executeCommand, Modifier <T> modifier)
        {
            // establishing a relationship with parent
            if (executeCommand.ParentRelationship != null)
            {
                for (int i = 0; i < executeCommand.ParentRelationship.Properties.Length; i++)
                {
                    string parentProperty = executeCommand.ParentRelationship.Properties[i];
                    object value          = executeCommand.ParentPropertyValues[parentProperty];
                    string property       = executeCommand.ParentRelationship.RelatedProperties[i];
                    if (executeCommand.PropertyValues.ContainsKey(property))
                    {
                        executeCommand.PropertyValues[property] = value;
                    }
                    else
                    {
                        executeCommand.PropertyValues.Add(property, value);
                    }
                }
            }

            // Sequence
            foreach (XElement propertySchema in executeCommand.EntitySchema.Elements(SchemaVocab.Property).Where(p => p.Attribute(SchemaVocab.Sequence) != null))
            {
                if (propertySchema.Attribute(SchemaVocab.AutoIncrement) != null && propertySchema.Attribute(SchemaVocab.AutoIncrement).Value == "true")
                {
                    continue;
                }

                string propertyName = propertySchema.Attribute(SchemaVocab.Name).Value;

                // provided by user
                if (executeCommand.PropertyValues.ContainsKey(propertyName))
                {
                    if (executeCommand.PropertyValues[propertyName] != null)
                    {
                        continue;
                    }
                }

                string sequenceName = propertySchema.Attribute(SchemaVocab.Sequence).Value;

                string seq_sql  = ModificationGenerator.GenerateFetchSequenceStatement(sequenceName);
                object sequence = UnderlyingDatabase.ExecuteScalar(seq_sql);

                if (executeCommand.PropertyValues.ContainsKey(propertyName))
                {
                    executeCommand.PropertyValues[propertyName] = sequence;
                }
                else
                {
                    executeCommand.PropertyValues.Add(propertyName, sequence);
                }
                modifier.SetObjectValue(executeCommand.AggregNode, propertyName, sequence);
            }

            // non-ManyToMany
            if (executeCommand.EntitySchema.Attribute(SchemaVocab.Name).Value == executeCommand.Entity)
            {
                // patch up SetDefaultValues
                foreach (KeyValuePair <string, object> pair in executeCommand.PropertyValues)
                {
                    modifier.SetObjectValue(executeCommand.AggregNode, pair.Key, pair.Value);
                }
            }

            // raise inserting event
            InsertingEventArgs <T> args = new InsertingEventArgs <T>(executeCommand.AggregNode, executeCommand.Entity, executeCommand.Schema, executeCommand.Path, executeCommand.Aggreg);

            OnInserting(args);

            // non-ManyToMany
            if (executeCommand.EntitySchema.Attribute(SchemaVocab.Name).Value == executeCommand.Entity)
            {
                // synchronize propertyValues with modified aggregNode OnInserting
                SynchronizePropertyValues(executeCommand, modifier);
            }

            //
            modifier.CheckConstraints(executeCommand);

            // GenerateInsertStatement
            string sql = ModificationGenerator.GenerateInsertStatement(executeCommand.PropertyValues, executeCommand.EntitySchema,
                                                                       out IReadOnlyDictionary <string, object> dbParameterValues);

            DbParameter[] dbParameters = UnderlyingDatabase.CreateParameters(dbParameterValues);

            // AutoIncrement
            int      affected;
            XElement autoPropertySchema = executeCommand.EntitySchema.Elements(SchemaVocab.Property).FirstOrDefault(p =>
                                                                                                                    p.Attribute(SchemaVocab.AutoIncrement) != null && p.Attribute(SchemaVocab.AutoIncrement).Value == "true");

            if (autoPropertySchema == null)
            {
                affected = UnderlyingDatabase.ExecuteSqlCommand(sql, dbParameters);
            }
            else
            {
                affected = UnderlyingDatabase.ExecuteInsertCommand(sql, dbParameters, out object autoIncrementValue);

                string propertyName = autoPropertySchema.Attribute(SchemaVocab.Name).Value;
                if (executeCommand.PropertyValues.ContainsKey(propertyName))
                {
                    executeCommand.PropertyValues[propertyName] = autoIncrementValue;
                }
                else
                {
                    executeCommand.PropertyValues.Add(propertyName, autoIncrementValue);
                }

                // non-ManyToMany
                if (executeCommand.EntitySchema.Attribute(SchemaVocab.Name).Value == executeCommand.Entity)
                {
                    modifier.SetObjectValue(executeCommand.AggregNode, propertyName, autoIncrementValue);
                }
            }

            // raise inserted event
            InsertedEventArgs <T> args1 = new InsertedEventArgs <T>(executeCommand.AggregNode, executeCommand.Entity, executeCommand.Schema, executeCommand.Path, executeCommand.Aggreg);

            OnInserted(args1);

            foreach (SQLStatment statment in args1.After)
            {
                int i = UnderlyingDatabase.ExecuteSqlCommand(statment.Sql, statment.Parameters);
            }

            return(affected);
        }
 protected void OnInserting(InsertingEventArgs <T> args)
 {
     Inserting?.Invoke(this, args);
 }