anchor.diff:              | NamedValue(cypherExpr, paramName, value) ->
                   cypher.Create(cypherExpr).WithParam(paramName, value)
               | Anonymous(_) -> failwith "Can't create anonymous nodes"
  +
  +        member x.Merge(cypher: ICypherFluentQuery) =
  +            match x with
  +            | NamedValue(_cypherExpr, paramName, value) ->
  +                match NodeExpr.TryFindNeo4jKey value with
  +                | Some (keyName, keyValue) ->
  +                    let mergeExpr =
  +                        sprintf
  +                            "(%s:%s {%s: %A})"
  +                            paramName (value.GetType().Name) keyName keyValue
  +
  +                    cypher.Merge(mergeExpr)
  +                          .OnCreate()
  +                          .Set(sprintf "%s = {__arg}" paramName)
  +                          .WithParam("__arg", value)
  +                | None -> failwith "Value should have a unique Neo4jKey attribute"
  +
  +            | Var(_) -> failwith "Can't merge node whose value is unknown before running the query"
  +            | Anonymous(_) -> failwith "Can't merge anonymous nodes"
  +
  +        static member private TryFindNeo4jKey (entity: obj) =
  +            let properties = entity.GetType().GetProperties()
  +            properties
  +            |> Array.tryPick (fun prop ->
  +                prop.CustomAttributes
  +                |> Seq.tryPick (fun attr ->
  +                    if attr.AttributeType = typeof<Neo4jKeyAttribute> then
  +                        Some (prop.Name, prop.GetValue(entity))
  +                    else
  +                        None
  +                )
  +            )
   
       [<RequireQualifiedAccess>]
       [<NoComparison>]
  
positive.code:     let inline (|DeclareRelationshipCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ declareRelationship @> (_, [relType], _) -> Some relType
          | _ -> None
  
      let inline (|IsNodeExpr|_|) expr: Option<NodeExpr> =
          match expr with
          | Var(var) -> Some (NodeExpr.Var(var))
          | ValueWithName(value, typ, name)
          | Coerce(ValueWithName(value, typ, name), _) ->
              // TODO denisok: extract constant
              let paramName = sprintf "__neo4jnode__%s" name
              let cypherExpr = sprintf "(%s:%s {%s})" name typ.Name paramName
              Some (NodeExpr.NamedValue(cypherExpr, paramName, value))
          | DeclareNodeCall(nodeType) -> Some (NodeExpr.Anonymous(nodeType))
          | _ ->
              debug "%O" expr
              None
  
      let inline (|IsRelExpr|_|) expr: Option<RelExpr> =
          match expr with
          | Var(var) -> Some (RelExpr.Var(var))
          | ValueWithName(value, typ, name) -> Some (RelExpr.NamedValue(name, typ, value))
          | DeclareRelationshipCall typ ->
              let cypherExpr = sprintf "[:%s]" typ.Name
              Some (RelExpr.TypedPattern(cypherExpr))
          | _ ->
              debug "%O" expr
              None
  
      let inline (|CreateNodeCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ createNode @>
              (_, _, [IsNodeExpr(NodeExpr.NamedValue _ as nodeExpr)]) ->
              debug "Create node: %A" nodeExpr
              Some nodeExpr
          | _ -> None
  
      let inline (|MatchNodeCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ matchNode @> (_, _, [nodeArg]) -> Some nodeArg
          | _ -> None
  
      let (|IsMatchRelationClause|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ matchRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.LeftOrRightRel(nodeExpr1, relExpr, nodeExpr2))
          | SpecificCall <@ matchRightRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.RightRel(nodeExpr1, relExpr, nodeExpr2, false))
          | SpecificCall <@ matchLeftRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.LeftRel(nodeExpr1, relExpr, nodeExpr2, false))
          | _ -> None
  
      let inline (|CreateRelationCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ createRightRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.RightRel(nodeExpr1, relExpr, nodeExpr2, isUnique=false))
  
          | SpecificCall <@ createUniqueRightRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.RightRel(nodeExpr1, relExpr, nodeExpr2, isUnique=true))
  
          | SpecificCall <@ createLeftRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.LeftRel(nodeExpr1, relExpr, nodeExpr2, isUnique=false))
  
          | SpecificCall <@ createUniqueLeftRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.LeftRel(nodeExpr1, relExpr, nodeExpr2, isUnique=true))
  
          | _ -> None
  
      let inline (|MergeRelationCall|_|) expr =
          match expr with
          | SpecificCall <@ mergeRightRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.RightRel(nodeExpr1, relExpr, nodeExpr2, isUnique=false))
          | SpecificCall <@ mergeLeftRelation @> (_, _, [IsNodeExpr(nodeExpr1); IsRelExpr(relExpr); IsNodeExpr(nodeExpr2)]) ->
              Some (CypherPattern.LeftRel(nodeExpr1, relExpr, nodeExpr2, isUnique=false))
          | _ -> None
  
      let inline (|DeleteNodeCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ deleteNode @> (_, _, [node]) -> Some node
          | _ -> None
  
      let inline (|DeleteRelationshipCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ deleteRelationship @> (_, _, [rel]) -> Some rel
          | _ -> None
  
      let inline (|WhereCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ where @> (_, _, [arg]) -> Some arg
          | _ -> None
  
      let inline (|ReturnResultsCall|_|) (callExpr: Expr) =
          match callExpr with
          | SpecificCall <@ returnResults @> (_,_,[returnArg]) -> Some returnArg
          | _ -> None
  
      let (|PropertyGetChain|_|) (expr: Expr) =
  
negative.code: 
      let private executeMerge (cypher: ICypherFluentQuery) mergeExpr =
          match mergeExpr with
          | MergeNodeCall nodeExpr -> nodeExpr.Merge(cypher)
          | MergeRelationCall patternExpr -> patternExpr.Merge(cypher)
          | _ -> unsupportedScenario "MERGE expression" mergeExpr
  
  