NgBatis ORM Framework for NebulaGraph

repository·master·Indexed 41 days ago

https://github.com/nebula-contrib/ngbatis

A Spring Boot-based ORM framework for NebulaGraph inspired by MyBatis. It supports nGQL composition via XML mapper files, a DAO pattern similar to MyBatis-Plus using NebulaDaoBasic, and entity direct search through GraphBaseVertex and GraphBaseEdge. Features include support for Geo types, Beetl template functions, and a compatibility matrix for JDK, Spring Boot, and nebula-java versions.

Tokens
36.8K
Snippets
90
Records
135
Agent score
99%

What's inside NgBatis

  1. What is NgBatis

    master

    NgBatis is a database ORM (Object-Relational Mapping) framework designed for Nebula Graph using Spring Boot. It is designed to follow the usage patterns of MyBatis, allowing developers to compose nGQL queries easily.

    Key features include:

    • MyBatis-style usage: Compose nGQL queries via mappers.
    • MyBatis-Plus-style usage: Provides frequently-used operations for single tables, vertices, and edges.
    • Graph-specific operations: Includes basic query methods for entity-relationship operations specific to graph databases.

    If you prefer a JPA-style approach instead of MyBatis, consider using graph-ocean instead.

  2. Overview of NgBatis

    master

    NgBatis is a database ORM (Object-Relational Mapping) framework built on top of NebulaGraph and Spring Boot. It is designed to provide a development experience similar to MyBatis, allowing developers to use nGQL (Nebula Graph Query Language) within XML templates. It also incorporates features similar to MyBatis-Plus, providing de-facto operations for single tables, vertices, and edges.

    Key features include:

    • Templating: Uses the Beetl template engine to allow dynamic nGQL queries via placeholder substitution in XML files.
    • ORM Support: Supports standard javax.persistence.* annotations for object-relational mapping.
    • Built-in CRUD: Provides basic CRUD operations through the NebulaDaoBasic<T, ID> base class.
  3. Understand NgBatis development modes

    master

    NgBatis provides three primary ways to interact with Nebula Graph, depending on your complexity requirements:

    1. MyBatis-plus style: Inherit from a provided base class in your DAO. This allows you to perform CRUD operations (Create, Read, Update, Delete) on single vertices or edges without writing any nGQL manually.
    2. MyBatis style: Write custom, complex nGQL or Cypher queries for advanced business logic and data writing.
    3. Entity Direct Query: Call provided query methods directly on entity objects. This mode is the simplest and allows you to skip the manual POJO preparation required for the other two modes.

    Note: For the MyBatis-plus and MyBatis styles, you must define POJO classes to map your graph schema to Java objects.

  4. Implement multi-tag entities using class inheritance

    master

    In NgBatis, you can implement multi-tag functionality by using Java class inheritance. When an entity class extends another class (e.g., Employee extends Person), NgBatis allows you to perform operations that affect multiple tags simultaneously.

    Key behaviors:

    • Insert: An insert operation can write properties from both the child class (Employee) and the parent class (Person) to the database in a single step.
    • Select: A select operation can read properties from both classes. However, if the node in the database possesses other tags not covered by this inheritance hierarchy, those additional properties will not be read.
    @Data
    @Table(name = "employee")
    public class Employee extends Person {
      private String position;
    }
  5. Use Beetl loop syntax for dynamic queries and batch processing

    master

    NgBatis uses Beetl loop syntax for dynamic query generation and batch processing within XML mapper files. Unlike MyBatis which uses <% %> tags, NgBatis uses @ as the prefix for loop and conditional statements.

    Syntax Transformation:

    • MyBatis: <% for (item in list) { ... } %>
    • NgBatis: @for (item in list) { ... @}

    Common loop patterns include looping over a Map to build dynamic WHERE clauses and looping over a List to generate multiple INSERT statements for batch processing.

  6. Access loop metadata using the LP suffix

    master

    When using loops in NgBatis (specifically for Nebula v3.2.0+), you can access metadata about the current iteration by appending LP to the loop variable name. This allows you to reference the original parameter index or collection properties within the loop body.

    If your loop variable is xxx, the available metadata properties are:

    • xxxLP.index: Current index, starting from 1
    • xxxLP.dataIndex: Current index, starting from 0
    • xxxLP.size: Length of the collection
    • xxxLP.first: Boolean, true if it is the first element
    • xxxLP.last: Boolean, true if it is the last element
    • xxxLP.even: Boolean, true if the index is even
    • xxxLP.odd: Boolean, true if the index is odd

    Example Usage for Parameter Passing: To pass the specific parameter variable name to the database during a loop, use the dataIndex property:

    <insert id="insertPersonList">
        @for ( p in personList ) {
          INSERT VERTEX `person` ( name, gender )
            VALUES '${ p.name }' : ( '$personList[${pLP.dataIndex}].name', '$personList[${pLP.dataIndex}].gender' );
        @}
    </insert>
    <insert id="insertPersonList">
        @for ( p in personList ) {
          INSERT VERTEX `person` ( name, gender )
            VALUES '${ p.name }' : ( '$personList[${pLP.dataIndex}].name', '$personList[${pLP.dataIndex}].gender' );
        @}
    </insert>
  7. Use Object-Graph Mapping (OGM) for direct entity queries

    master

    NgBatis supports OGM, allowing you to execute queries directly from entity instances. To use this, your entities must extend specific base classes.

    Vertex Entities

    Extend GraphBaseVertex and use the @Tag annotation to specify the Tag name.

    Edge Entities

    Extend GraphBaseEdge and use the @EdgeType annotation. You can optionally use @Id, @SrcId, and @DstId to map properties to the edge's identity and connection points.

    Querying

    Once defined, you can call methods directly on the entity instance to perform lookups based on properties, tags, or topology.

    @Tag(name = "player")
    public class Player extends GraphBaseVertex {
      @Id
      private String id;
      private String name;
      private Integer age;
    }
    
    @EdgeType(name = "serve")
    public class Serve extends GraphBaseEdge {
      @Id 
      private Long rank;
      @SrcId
      private String srcId;
      @DstId
      private String dstId;
      @Column(name = "start_year")
      private Integer startYear;
    }
  8. Understand the NgBatis proxy method invocation flow

    master

    When a developer calls a method on a generated DAO interface (e.g., XXXDao), the following internal execution flow occurs:

    1. Proxy Interception: The MapperProxy.invoke method intercepts the call, receiving the interface name, method name, and argument list.
    2. Method Model Selection:
      • Standard Methods: The proxy directly invokes the method model with the provided arguments.
      • Pagination Methods: The proxy first retrieves and invokes the Count method model, followed by the Page method model.
    3. Parameter & Template Resolution:
      • ArgsResolver converts the argument list into a Map type for easier access.
      • TextResolver performs template parameter replacement (mapping arguments to the query template).
    4. Execution & Mapping:
      • The system executes the query via Session.executeWithParameter.
      • ResultResolver performs the ORM (Object-Relational Mapping) step, converting the raw result set into the data structure required by the method's return type.
    5. Return: The processed result is returned to the caller as the expected type.
  9. Use Loop Helper (LP) variables for Nebula v3.2.0+

    master

    For Nebula Graph version 3.2.0 and above, you can pass parameter variable names directly to the database during data modification.

    When using a loop, you can access a special helper object by appending LP to the loop variable name (e.g., if the loop is @for ( p in personList ), the helper is pLP). This allows you to reference the original collection and the specific index in the generated nGQL.

    Available LP properties:

    • xxxLP.index: Current index (starts from 1)
    • xxxLP.dataIndex: Current index (starts from 0)
    • xxxLP.size: Total size of the collection
    • xxxLP.first: Boolean, true if it is the first element
    • xxxLP.last: Boolean, true if it is the last element
    • xxxLP.even: Boolean, true if the index is even
    • xxxLP.odd: Boolean, true if the index is odd
    <!-- PersonDao.xml for Nebula >= v3.2.0 -->
    <insert id="insertPersonList">
        @for ( p in personList ) {
          INSERT VERTEX `person` ( name, gender )
            VALUES '${ p.name }' : ( '$personList[${pLP.dataIndex}].name', '$personList[${pLP.dataIndex}].gender' );
        @}
    </insert>
  10. Understand the three ways to access Nebula with NgBatis

    master

    NgBatis provides three distinct interaction models for developers to access Nebula Graph data:

    1. Basic DAO (MyBatis-plus style): Extend a basic DAO to perform operations on single tables (vertices or edges) without writing any nGQL. This is ideal for standard CRUD operations.
    2. Custom nGQL (MyBatis style): Write complex nGQL or Cypher queries to handle sophisticated read or write operations.
    3. Entity Direct Query: Directly call provided query methods on entity objects for data inspection. This method is the most streamlined and allows you to skip the manual preparation of DAOs and custom queries.

    Note: If you choose to use the Basic DAO or Custom nGQL methods, you must prepare your Nebula schema and corresponding Java POJOs as described in the setup guides.