diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py
index 5443e178c0f726be5b55e7955a6dc7b575d9f53a..e35f246b6b79985bdcaff3cd71acf2f5a9d85136 100644
--- a/src/context/service/database/ConfigRule.py
+++ b/src/context/service/database/ConfigRule.py
@@ -12,16 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import datetime, logging
+import datetime, json, logging
 from sqlalchemy import delete
 from sqlalchemy.dialects.postgresql import insert
 from sqlalchemy.orm import Session
-from typing import Dict, List, Optional
+from typing import Dict, List, Optional, Set
 from common.proto.context_pb2 import ConfigRule
 from common.tools.grpc.Tools import grpc_message_to_json_string
-from .models.enums.ConfigAction import grpc_to_enum__config_action
+from .models.enums.ConfigAction import ORM_ConfigActionEnum, grpc_to_enum__config_action
 from .models.ConfigRuleModel import ConfigRuleKindEnum, ConfigRuleModel
-from .uuids._Builder import get_uuid_random
+from .uuids._Builder import get_uuid_from_string
+from .uuids.EndPoint import endpoint_get_uuid
 
 LOGGER = logging.getLogger(__name__)
 
@@ -31,173 +32,106 @@ def compose_config_rules_data(
 ) -> List[Dict]:
     dict_config_rules : List[Dict] = list()
     for position,config_rule in enumerate(config_rules):
-        configrule_uuid = get_uuid_random()
         str_kind = config_rule.WhichOneof('config_rule')
+        kind = ConfigRuleKindEnum._member_map_.get(str_kind.upper()) # pylint: disable=no-member
         dict_config_rule = {
-            'configrule_uuid': configrule_uuid,
-            'position'       : position,
-            'kind'           : ConfigRuleKindEnum._member_map_.get(str_kind.upper()), # pylint: disable=no-member
-            'action'         : grpc_to_enum__config_action(config_rule.action),
-            'data'           : grpc_message_to_json_string(getattr(config_rule, str_kind, {})),
-            'created_at'     : now,
-            'updated_at'     : now,
+            'position'  : position,
+            'kind'      : kind,
+            'action'    : grpc_to_enum__config_action(config_rule.action),
+            'data'      : grpc_message_to_json_string(getattr(config_rule, str_kind, {})),
+            'created_at': now,
+            'updated_at': now,
         }
-        if device_uuid  is not None: dict_config_rule['device_uuid' ] = device_uuid
-        if service_uuid is not None: dict_config_rule['service_uuid'] = service_uuid
-        if slice_uuid   is not None: dict_config_rule['slice_uuid'  ] = slice_uuid
+
+        parent_uuid = None
+        if device_uuid is not None:
+            dict_config_rule['device_uuid'] = device_uuid
+            parent_uuid = device_uuid
+        elif service_uuid is not None:
+            dict_config_rule['service_uuid'] = service_uuid
+            parent_uuid = service_uuid
+        elif slice_uuid is not None:
+            dict_config_rule['slice_uuid'] = slice_uuid
+            parent_uuid = slice_uuid
+        else:
+            MSG = 'Parent for ConfigRule({:s}) cannot be identified '+\
+                  '(device_uuid={:s}, service_uuid={:s}, slice_uuid={:s})'
+            str_config_rule = grpc_message_to_json_string(config_rule)
+            raise Exception(MSG.format(str_config_rule, str(device_uuid), str(service_uuid), str(slice_uuid)))
+        
+        configrule_name = None
+        if kind == ConfigRuleKindEnum.CUSTOM:
+            configrule_name = config_rule.custom.resource_key
+        elif kind == ConfigRuleKindEnum.ACL:
+            endpoint_uuid = endpoint_get_uuid(config_rule.acl.endpoint_id, allow_random=False)
+            rule_set_name = config_rule.acl.rule_set.name
+            configrule_name = '{:s}/{:s}'.format(endpoint_uuid, rule_set_name)
+        else:
+            MSG = 'Name for ConfigRule({:s}) cannot be inferred '+\
+                  '(device_uuid={:s}, service_uuid={:s}, slice_uuid={:s})'
+            str_config_rule = grpc_message_to_json_string(config_rule)
+            raise Exception(MSG.format(str_config_rule, str(device_uuid), str(service_uuid), str(slice_uuid)))
+
+        configrule_uuid = get_uuid_from_string(configrule_name, prefix_for_name=parent_uuid)
+        dict_config_rule['configrule_uuid'] = configrule_uuid
+
         dict_config_rules.append(dict_config_rule)
     return dict_config_rules
 
 def upsert_config_rules(
     session : Session, config_rules : List[Dict],
     device_uuid : Optional[str] = None, service_uuid : Optional[str] = None, slice_uuid : Optional[str] = None,
-) -> List[bool]:
-    # TODO: do not delete all rules; just add-remove as needed
-    stmt = delete(ConfigRuleModel)
-    if device_uuid  is not None: stmt = stmt.where(ConfigRuleModel.device_uuid  == device_uuid )
-    if service_uuid is not None: stmt = stmt.where(ConfigRuleModel.service_uuid == service_uuid)
-    if slice_uuid   is not None: stmt = stmt.where(ConfigRuleModel.slice_uuid   == slice_uuid  )
-    session.execute(stmt)
+) -> bool:
+    uuids_to_delete : Set[str] = set()
+    uuids_to_upsert : Dict[str, int] = dict()
+    rules_to_upsert : List[Dict] = list()
+    for config_rule in config_rules:
+        if config_rule['action'] == ORM_ConfigActionEnum.SET:
+            configrule_uuid = config_rule['configrule_uuid']
+            position = uuids_to_upsert.get(configrule_uuid)
+            if position is None:
+                # if not added, add it
+                rules_to_upsert.append(config_rule)
+                uuids_to_upsert[config_rule['configrule_uuid']] = len(rules_to_upsert) - 1
+            else:
+                # if already added, update occurrence
+                rules_to_upsert[position] = config_rule
+        elif config_rule['action'] == ORM_ConfigActionEnum.DELETE:
+            uuids_to_delete.add(config_rule['configrule_uuid'])
+        else:
+            MSG = 'Action for ConfigRule({:s}) is not supported '+\
+                  '(device_uuid={:s}, service_uuid={:s}, slice_uuid={:s})'
+            str_config_rule = json.dumps(config_rule)
+            raise Exception(MSG.format(str_config_rule, str(device_uuid), str(service_uuid), str(slice_uuid)))
+
+    #LOGGER.warning('uuids_to_delete={:s}'.format(str(uuids_to_delete)))
+    #LOGGER.warning('rules_to_upsert={:s}'.format(str(rules_to_upsert)))
 
-    configrule_updates = []
-    if len(config_rules) > 0:
-        stmt = insert(ConfigRuleModel).values(config_rules)
-        #stmt = stmt.on_conflict_do_update(
-        #    index_elements=[ConfigRuleModel.configrule_uuid],
-        #    set_=dict(
-        #        updated_at = stmt.excluded.updated_at,
-        #    )
-        #)
+    delete_affected = False
+    upsert_affected = False
+
+    if len(uuids_to_delete) > 0:
+        stmt = delete(ConfigRuleModel)
+        if device_uuid  is not None: stmt = stmt.where(ConfigRuleModel.device_uuid  == device_uuid )
+        if service_uuid is not None: stmt = stmt.where(ConfigRuleModel.service_uuid == service_uuid)
+        if slice_uuid   is not None: stmt = stmt.where(ConfigRuleModel.slice_uuid   == slice_uuid  )
+        stmt = stmt.where(ConfigRuleModel.configrule_uuid.in_(uuids_to_delete))
+        configrule_deletes = session.execute(stmt)#.fetchall()
+        delete_affected = int(configrule_deletes.rowcount) > 0
+
+    if len(rules_to_upsert) > 0:
+        stmt = insert(ConfigRuleModel).values(rules_to_upsert)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[ConfigRuleModel.configrule_uuid],
+            set_=dict(
+                position   = stmt.excluded.position,
+                action     = stmt.excluded.action,
+                data       = stmt.excluded.data,
+                updated_at = stmt.excluded.updated_at,
+            )
+        )
         stmt = stmt.returning(ConfigRuleModel.created_at, ConfigRuleModel.updated_at)
         configrule_updates = session.execute(stmt).fetchall()
+        upsert_affected = any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
 
-    return configrule_updates
-
-#Union_SpecificConfigRule = Union[
-#    ConfigRuleCustomModel, ConfigRuleAclModel
-#]
-#
-#def set_config_rule(
-#    database : Database, db_config : ConfigModel, position : int, resource_key : str, resource_value : str,
-#): # -> Tuple[ConfigRuleModel, bool]:
-#
-#    str_rule_key_hash = fast_hasher(resource_key)
-#    str_config_rule_key = key_to_str([db_config.config_uuid, str_rule_key_hash], separator=':')
-#
-#    data = {'config_fk': db_config, 'position': position, 'action': ORM_ConfigActionEnum.SET, 'key': resource_key,
-#            'value': resource_value}
-#    to_add = ConfigRuleModel(**data)
-#
-#    result = database.create_or_update(to_add)
-#    return result
-#Tuple_ConfigRuleSpecs = Tuple[Type, str, Dict, ConfigRuleKindEnum]
-#
-#def parse_config_rule_custom(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
-#    config_rule_class = ConfigRuleCustomModel
-#    str_config_rule_id = grpc_config_rule.custom.resource_key
-#    config_rule_data = {
-#        'key'  : grpc_config_rule.custom.resource_key,
-#        'value': grpc_config_rule.custom.resource_value,
-#    }
-#    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.CUSTOM
-#
-#def parse_config_rule_acl(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
-#    config_rule_class = ConfigRuleAclModel
-#    grpc_endpoint_id = grpc_config_rule.acl.endpoint_id
-#    grpc_rule_set = grpc_config_rule.acl.rule_set
-#    device_uuid = grpc_endpoint_id.device_id.device_uuid.uuid
-#    endpoint_uuid = grpc_endpoint_id.endpoint_uuid.uuid
-#    str_endpoint_key = '/'.join([device_uuid, endpoint_uuid])
-#    #str_endpoint_key, db_endpoint = get_endpoint(database, grpc_endpoint_id)
-#    str_config_rule_id = ':'.join([str_endpoint_key, grpc_rule_set.name])
-#    config_rule_data = {
-#        #'endpoint_fk': db_endpoint,
-#        'endpoint_id': grpc_message_to_json_string(grpc_endpoint_id),
-#        'acl_data': grpc_message_to_json_string(grpc_rule_set),
-#    }
-#    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.ACL
-#
-#CONFIGRULE_PARSERS = {
-#    'custom': parse_config_rule_custom,
-#    'acl'   : parse_config_rule_acl,
-#}
-#
-#Union_ConfigRuleModel = Union[
-#    ConfigRuleCustomModel, ConfigRuleAclModel,
-#]
-#
-#def set_config_rule(
-#    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule, position : int
-#) -> Tuple[Union_ConfigRuleModel, bool]:
-#    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
-#    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
-#    if parser is None:
-#        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
-#            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
-#
-#    # create specific ConfigRule
-#    config_rule_class, str_config_rule_id, config_rule_data, config_rule_kind = parser(database, grpc_config_rule)
-#    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
-#    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
-#    result : Tuple[Union_ConfigRuleModel, bool] = update_or_create_object(
-#        database, config_rule_class, str_config_rule_key, config_rule_data)
-#    db_specific_config_rule, updated = result
-#
-#    # create generic ConfigRule
-#    config_rule_fk_field_name = 'config_rule_{:s}_fk'.format(config_rule_kind.value)
-#    config_rule_data = {
-#        'config_fk': db_config, 'kind': config_rule_kind, 'position': position,
-#        'action': ORM_ConfigActionEnum.SET,
-#        config_rule_fk_field_name: db_specific_config_rule
-#    }
-#    result : Tuple[ConfigRuleModel, bool] = update_or_create_object(
-#        database, ConfigRuleModel, str_config_rule_key, config_rule_data)
-#    db_config_rule, updated = result
-#
-#    return db_config_rule, updated
-#
-#def delete_config_rule(
-#    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule
-#) -> None:
-#    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
-#    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
-#    if parser is None:
-#        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
-#            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
-#
-#    # delete generic config rules; self deletes specific config rule
-#    _, str_config_rule_id, _, config_rule_kind = parser(database, grpc_config_rule)
-#    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
-#    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
-#    db_config_rule : Optional[ConfigRuleModel] = get_object(
-#        database, ConfigRuleModel, str_config_rule_key, raise_if_not_found=False)
-#    if db_config_rule is None: return
-#    db_config_rule.delete()
-#
-#def update_config(
-#    database : Database, db_parent_pk : str, config_name : str, grpc_config_rules
-#) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]:
-#
-#    str_config_key = key_to_str([config_name, db_parent_pk], separator=':')
-#    result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key)
-#    db_config, created = result
-#
-#    db_objects = [(db_config, created)]
-#
-#    for position,grpc_config_rule in enumerate(grpc_config_rules):
-#        action = grpc_to_enum__config_action(grpc_config_rule.action)
-#
-#        if action == ORM_ConfigActionEnum.SET:
-#            result : Tuple[ConfigRuleModel, bool] = set_config_rule(
-#                database, db_config, grpc_config_rule, position)
-#            db_config_rule, updated = result
-#            db_objects.append((db_config_rule, updated))
-#        elif action == ORM_ConfigActionEnum.DELETE:
-#            delete_config_rule(database, db_config, grpc_config_rule)
-#        else:
-#            msg = 'Unsupported Action({:s}) for ConfigRule({:s})'
-#            str_action = str(ConfigActionEnum.Name(action))
-#            str_config_rule = grpc_message_to_json_string(grpc_config_rule)
-#            raise AttributeError(msg.format(str_action, str_config_rule))
-#
-#    return db_objects
+    return delete_affected or upsert_affected
diff --git a/src/context/service/database/Constraint.py b/src/context/service/database/Constraint.py
index 2880c05a85dbde7c3af87d6766375862767611a7..82629b25c8453a8b499635a538ba776189b6116b 100644
--- a/src/context/service/database/Constraint.py
+++ b/src/context/service/database/Constraint.py
@@ -47,14 +47,14 @@ def compose_constraints_data(
 def upsert_constraints(
     session : Session, constraints : List[Dict],
     service_uuid : Optional[str] = None, slice_uuid : Optional[str] = None
-) -> List[bool]:
+) -> bool:
     # TODO: do not delete all constraints; just add-remove as needed
     stmt = delete(ConstraintModel)
     if service_uuid is not None: stmt = stmt.where(ConstraintModel.service_uuid == service_uuid)
     if slice_uuid   is not None: stmt = stmt.where(ConstraintModel.slice_uuid   == slice_uuid  )
     session.execute(stmt)
 
-    constraint_updates = []
+    changed = False
     if len(constraints) > 0:
         stmt = insert(ConstraintModel).values(constraints)
         #stmt = stmt.on_conflict_do_update(
@@ -65,8 +65,9 @@ def upsert_constraints(
         #)
         stmt = stmt.returning(ConstraintModel.created_at, ConstraintModel.updated_at)
         constraint_updates = session.execute(stmt).fetchall()
+        changed = any([(updated_at > created_at) for created_at,updated_at in constraint_updates])
 
-    return constraint_updates
+    return changed
 
 
 #    def set_constraint(self, db_constraints: ConstraintsModel, grpc_constraint: Constraint, position: int
diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py
index 07d1c76061d8b228cf39ddc06d358190bfce48fd..cde8751b417072f3f0de53217dab99308ea882f3 100644
--- a/src/context/service/database/Device.py
+++ b/src/context/service/database/Device.py
@@ -20,6 +20,7 @@ from sqlalchemy_cockroachdb import run_transaction
 from typing import Dict, List, Optional, Set, Tuple
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
 from common.proto.context_pb2 import Device, DeviceId
+from common.tools.grpc.Tools import grpc_message_to_json_string
 from common.tools.object_factory.Device import json_device_id
 from .models.DeviceModel import DeviceModel
 from .models.EndPointModel import EndPointModel
@@ -136,6 +137,7 @@ def device_set(db_engine : Engine, request : Device) -> Tuple[Dict, bool]:
         created_at,updated_at = session.execute(stmt).fetchone()
         updated = updated_at > created_at
 
+        updated_endpoints = False
         if len(endpoints_data) > 0:
             stmt = insert(EndPointModel).values(endpoints_data)
             stmt = stmt.on_conflict_do_update(
@@ -149,17 +151,16 @@ def device_set(db_engine : Engine, request : Device) -> Tuple[Dict, bool]:
             )
             stmt = stmt.returning(EndPointModel.created_at, EndPointModel.updated_at)
             endpoint_updates = session.execute(stmt).fetchall()
-            updated = updated or any([(updated_at > created_at) for created_at,updated_at in endpoint_updates])
+            updated_endpoints = any([(updated_at > created_at) for created_at,updated_at in endpoint_updates])
 
         if len(related_topologies) > 0:
             session.execute(insert(TopologyDeviceModel).values(related_topologies).on_conflict_do_nothing(
                 index_elements=[TopologyDeviceModel.topology_uuid, TopologyDeviceModel.device_uuid]
             ))
 
-        configrule_updates = upsert_config_rules(session, config_rules, device_uuid=device_uuid)
-        updated = updated or any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
+        changed_config_rules = upsert_config_rules(session, config_rules, device_uuid=device_uuid)
 
-        return updated
+        return updated or updated_endpoints or changed_config_rules
 
     updated = run_transaction(sessionmaker(bind=db_engine), callback)
     return json_device_id(device_uuid),updated
diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py
index 76a83053587aa8beb44c4d96771c3cfa46945b07..9b9e9a621446518aa0178d893decf46fbe427809 100644
--- a/src/context/service/database/Service.py
+++ b/src/context/service/database/Service.py
@@ -118,6 +118,7 @@ def service_set(db_engine : Engine, request : Service) -> Tuple[Dict, bool]:
         created_at,updated_at = session.execute(stmt).fetchone()
         updated = updated_at > created_at
 
+        # TODO: check if endpoints are changed
         if len(service_endpoints_data) > 0:
             stmt = insert(ServiceEndPointModel).values(service_endpoints_data)
             stmt = stmt.on_conflict_do_nothing(
@@ -125,13 +126,10 @@ def service_set(db_engine : Engine, request : Service) -> Tuple[Dict, bool]:
             )
             session.execute(stmt)
 
-        constraint_updates = upsert_constraints(session, constraints, service_uuid=service_uuid)
-        updated = updated or any([(updated_at > created_at) for created_at,updated_at in constraint_updates])
+        changed_constraints = upsert_constraints(session, constraints, service_uuid=service_uuid)
+        changed_config_rules = upsert_config_rules(session, config_rules, service_uuid=service_uuid)
 
-        configrule_updates = upsert_config_rules(session, config_rules, service_uuid=service_uuid)
-        updated = updated or any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
-
-        return updated
+        return updated or changed_constraints or changed_config_rules
 
     updated = run_transaction(sessionmaker(bind=db_engine), callback)
     return json_service_id(service_uuid, json_context_id(context_uuid)),updated
diff --git a/src/context/service/database/Slice.py b/src/context/service/database/Slice.py
index 84bfff34391ada943fc61caaa0789e8e4d8e270f..113af9aa41420382d34a95bbd4996b795e95e065 100644
--- a/src/context/service/database/Slice.py
+++ b/src/context/service/database/Slice.py
@@ -136,6 +136,7 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[Dict, bool]:
         created_at,updated_at = session.execute(stmt).fetchone()
         updated = updated_at > created_at
 
+        # TODO: check if endpoints are changed
         if len(slice_endpoints_data) > 0:
             stmt = insert(SliceEndPointModel).values(slice_endpoints_data)
             stmt = stmt.on_conflict_do_nothing(
@@ -143,6 +144,7 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[Dict, bool]:
             )
             session.execute(stmt)
 
+        # TODO: check if services are changed
         if len(slice_services_data) > 0:
             stmt = insert(SliceServiceModel).values(slice_services_data)
             stmt = stmt.on_conflict_do_nothing(
@@ -150,6 +152,7 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[Dict, bool]:
             )
             session.execute(stmt)
 
+        # TODO: check if subslices are changed
         if len(slice_subslices_data) > 0:
             stmt = insert(SliceSubSliceModel).values(slice_subslices_data)
             stmt = stmt.on_conflict_do_nothing(
@@ -157,13 +160,10 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[Dict, bool]:
             )
             session.execute(stmt)
 
-        constraint_updates = upsert_constraints(session, constraints, slice_uuid=slice_uuid)
-        updated = updated or any([(updated_at > created_at) for created_at,updated_at in constraint_updates])
+        changed_constraints = upsert_constraints(session, constraints, slice_uuid=slice_uuid)
+        changed_config_rules = upsert_config_rules(session, config_rules, slice_uuid=slice_uuid)
 
-        configrule_updates = upsert_config_rules(session, config_rules, slice_uuid=slice_uuid)
-        updated = updated or any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
-
-        return updated
+        return updated or changed_constraints or changed_config_rules
 
     updated = run_transaction(sessionmaker(bind=db_engine), callback)
     return json_slice_id(slice_uuid, json_context_id(context_uuid)),updated