コード例 #1
0
        /// <summary>
        /// Saves entity to mikrotik router. Does insert (/add) whan entity has empty id and update(/set + /unset) when id is present).
        /// Behavior of save is modified via <see cref="TikPropertyAttribute"/> on properties.
        /// See <see cref="TikPropertyAttribute.DefaultValue"/>, <see cref="TikPropertyAttribute.UnsetOnDefault"/>.
        /// </summary>
        /// <typeparam name="TEntity">Saved entitie type.</typeparam>
        /// <param name="connection">Tik connection used to save.</param>
        /// <param name="entity">Saved entity.</param>
        /// <param name="usedFieldsFilter">List of field names (on mikrotik) which should be modified. If is not null, only listed fields will be modified.</param>
        public static void Save <TEntity>(this ITikConnection connection, TEntity entity, IEnumerable <string> usedFieldsFilter = null)
            where TEntity : new()
        {
            var metadata = TikEntityMetadataCache.GetMetadata <TEntity>();

            EnsureNotReadonlyEntity(metadata);

            string id;

            if (metadata.IsSingleton)
            {
                id = null;
            }
            else
            {
                EnsureHasIdProperty(metadata);
                id = metadata.IdProperty.GetEntityValue(entity);
            }

            if (!metadata.IsSingleton && string.IsNullOrEmpty(id))
            {
                //create
                ITikCommand createCmd = connection.CreateCommand(metadata.EntityPath + "/add", TikCommandParameterFormat.NameValue);

                foreach (var property in metadata.Properties
                         .Where(pm => !pm.IsReadOnly)
                         .Where(pm => usedFieldsFilter == null || usedFieldsFilter.Contains(pm.FieldName, StringComparer.OrdinalIgnoreCase)))
                {
                    if (!property.HasDefaultValue(entity))
                    {
                        createCmd.AddParameter(property.FieldName, property.GetEntityValue(entity));
                    }
                }

                id = createCmd.ExecuteScalar();
                if (metadata.HasIdProperty)
                {
                    metadata.IdProperty.SetEntityValue(entity, id); // update saved id into entity
                }
            }
            else
            {
                //update (set+unset)
                ITikCommand setCmd = connection.CreateCommand(metadata.EntityPath + "/set", TikCommandParameterFormat.NameValue);

                if (!metadata.IsSingleton && usedFieldsFilter == null)
                {
                    //compare state on mikrotik and update different fields only
                    var unmodifiedEntity = connection.LoadById <TEntity>(id); //TODO some kind of "loaded entities" session cache could be used to avoid another load before save.
                    usedFieldsFilter = entity.GetDifferentFields(unmodifiedEntity);
                }

                List <string> fieldsToUnset = new List <string>();

                foreach (var property in metadata.Properties
                         .Where(pm => !pm.IsReadOnly)
                         .Where(pm => usedFieldsFilter == null || usedFieldsFilter.Contains(pm.FieldName, StringComparer.OrdinalIgnoreCase)))
                {
                    if (property.HasDefaultValue(entity) && property.UnsetOnDefault)
                    {
                        fieldsToUnset.Add(property.FieldName);
                    }
                    else
                    {
                        setCmd.AddParameter(property.FieldName, property.GetEntityValue(entity)); //full update (all values)
                    }
                }

                if (fieldsToUnset.Count > 0)
                {
                    // this should also work (see http://forum.mikrotik.com/viewtopic.php?t=28821 )
                    //ip/route/unset
                    //=.id = *1
                    //= value-name=routing-mark

                    foreach (string fld in fieldsToUnset)
                    {
                        ITikCommand unsetCmd = connection.CreateCommand(metadata.EntityPath + "/unset", TikCommandParameterFormat.NameValue);
                        unsetCmd.AddParameter(TikSpecialProperties.Id, id, TikCommandParameterFormat.NameValue);
                        unsetCmd.AddParameter(TikSpecialProperties.UnsetValueName, fld);

                        unsetCmd.ExecuteNonQuery();
                    }
                }
                if (setCmd.Parameters.Any())
                {
                    if (!metadata.IsSingleton)
                    {
                        setCmd.AddParameter(TikSpecialProperties.Id, id, TikCommandParameterFormat.NameValue);
                    }
                    setCmd.ExecuteNonQuery();
                }
            }
        }