LiteOrm在线文档

Expr JSON Serialization Format

LiteOrm’s ExprJsonConverter is easiest to understand when you think in two JSON shapes:

For learning, this order works well:

  1. start with the core markers such as $, #, @, and $where
  2. move to the side-by-side expression examples
  3. finish with the complete query example so the whole chain becomes clear

1. Core Marker Reference

1.1 Short Format Markers

Marker Meaning Example
! Negation (Not) {"!": {"#": "IsActive"}}
# Property reference {"#": "Name"} or {"#": "u.Name"}
$ Type/operator identifier {"$": "table"} or {"$": "=="}
$and Logical AND {"$and": [...]}
$or Logical OR {"$or": [...]}
@ Variable value {"@": 42} or {"@": "hello"}

1.2 Expr Comparison Operator Mapping

Expr Comparison Operator JSON Short Form
.Contains() contains
.EndsWith() endswith
.In() in
.Like() like
.NotContains() notcontains
.NotEndsWith() notendswith
.NotIn() notin
.NotLike() notlike
.RegexpLike() regexp
.NotRegexpLike() notregexp
.NotStartsWith() notstartswith
.StartsWith() startswith
< <
<= <=
<> !=
= ==
> >
>= >=

1.3 ExprType Type Reference

This table is aligned with the current implementation. Older notes may still show outdated names.

ExprType Description Short Marker Normal Mode $ Value
And Logic AND expression group $and "and"
Delete Delete segment, represents DELETE $delete "delete"
Foreign Foreign-key EXISTS expression $foreign "foreign"
From From segment, represents a data source $from "from"
Function Function call expression {"$":"func","ActualFunctionName":[...]} "func"
GenericSql SQL fragment generated via delegate or registration - "sql"
GroupBy Group-by segment, represents GROUP BY $group "group"
Having Having segment, represents HAVING $having "having"
Lambda Lambda will be parsed into internal expressions - -
LogicBinary Logic binary expression (comparisons) "$":"==", "$":"!=", "$":">", "$":">=", "$":"<", "$":"<=", "$":"in" "logic"
Not Logic NOT expression ! "not"
Or Logic OR expression group $or "or"
OrderBy Order-by segment, represents ORDER BY $orderby "orderby"
OrderByItem ORDER BY item - "orderbyitem"
Property Property (column) reference expression # "prop"
Section Pagination segment, represents LIMIT/OFFSET $section "section"
Select Select segment, represents a SELECT query $select "select"
SelectItem Select item, for SELECT column definition - "selectitem"
Table Table segment, represents a single table or subquery $table "table"
TableJoin Table join segment, represents a JOIN clause $join "join"
Unary Unary expression (for example DISTINCT or -a) - "unary"
Update Update segment, represents UPDATE $update "update"
Value Value expression @ (variable) or direct value (const) "value"
ValueBinary Value binary expression (arithmetic or concat) "$":"+","$":"-","$":"*", "$":"/, "$":"%", "$":"||" "bin"
ValueSet Value-set expression (for IN or CONCAT) - "set"
Where Filter segment, represents WHERE $where "where"

2. Short Format vs Normal Format Comparison

Use the examples below with one simple rule in mind:

2.1 Property Reference (PropertyExpr)

Short Format:

{"#": "Name"}
{"#": "u.Name"}

Normal Format:

{
  "$": "property",
  "PropertyName": "Name",
  "TableAlias": null
}

2.2 Value Expression (ValueExpr)

Short Format - IsConst=true (Constant Value):

42
"hello"

Mapped non-primitive value types use a typed wrapper so the CLR type survives round-tripping:

{"$datetime": "2024-01-15T10:30:45Z"}
{"$datetimeoffset": "2024-01-15T10:30:45+08:00"}
{"$timespan": "01:00:00"}
{"$guid": "6f9619ff-8b86-d011-b42d-00c04fc964ff"}
{"$bytes": "AQID/w=="}

Short Format - IsConst=false (Variable Value):

{"@": 42}
{"@": "variableName"}

For variable values, the same typed wrapper is used inside @:

{"@": {"$guid": "6f9619ff-8b86-d011-b42d-00c04fc964ff"}}
{"@": {"$bytes": "AQID/w=="}}

Normal Format - IsConst=true (Constant Value):

{
  "$": "value",
  "Value": 42,
  "IsConst": true
}

Normal Format - IsConst=false (Variable Value):

{
  "$": "value",
  "Value": 42,
  "IsConst": false
}

Currently, typed wrappers are only used for these mapped runtime types:

2.3 Logic Binary Expression (LogicBinaryExpr)

Short Format:

{
  "$": "==",
  "Left": {"#": "Age"},
  "Right": {"@": 18}
}

Normal Format:

{
  "$": "logic",
  "Operator": 0,
  "Left": {
    "$": "property",
    "PropertyName": "Age",
    "TableAlias": null
  },
  "Right": {
    "$": "value",
    "Value": 18,
    "IsConst": false
  }
}

2.4 AND Expression (AndExpr)

Short Format:

{
  "$and": [
    {"$": "==", "Left": {"#": "Status"}, "Right": {"@": "Pending"}},
    {"$": ">=", "Left": {"#": "TotalAmount"}, "Right": {"@": 300}}
  ]
}

Normal Format:

{
  "$": "and",
  "Items": [
    {
      "$": "logic",
      "Operator": 0,
      "Left": {"$": "property", "PropertyName": "Status"},
      "Right": {"$": "value", "Value": "Pending", "IsConst": false}
    },
    {
      "$": "logic",
      "Operator": 3,
      "Left": {"$": "property", "PropertyName": "TotalAmount"},
      "Right": {"$": "value", "Value": 300, "IsConst": false}
    }
  ]
}

2.5 NOT Expression (NotExpr)

Short Format:

{
  "!": {"$": "==", "Left": {"#": "IsActive"}, "Right": {"@": false}}
}

Normal Format:

{
  "$": "not",
  "Operand": {
    "$": "logic",
    "Operator": 0,
    "Left": {"$": "property", "PropertyName": "IsActive"},
    "Right": {"$": "value", "Value": false, "IsConst": false}
  }
}

2.6 SQL Segment (SqlSegment)

This is usually the hardest part to read because From -> Where -> OrderBy -> Section is nested layer by layer. Read the outer marker first, then inspect its Source and sibling properties.

Short Format - TableExpr:

{"$table": "LiteOrm.Tests.Models.TestUser"}

Short Format - TableExpr with Parameters:

{
  "$table": "LiteOrm.Tests.Models.TestUser",
  "TableArgs": ["2024", "01"],
  "Alias": "u"
}

Normal Format - TableExpr:

{
  "$": "table",
  "Type": "LiteOrm.Tests.Models.TestUser",
  "TableArgs": ["2024", "01"],
  "Alias": "u"
}

Note: FromExpr uses $from in short format and directly contains TableExpr ($table) plus Joins.

Short Format - FromExpr:

{
  "$from": {
    "$table": "LiteOrm.Tests.Models.TestUser",
    "TableArgs": ["2024", "01"],
    "Alias": "u"
  },
  "Joins": []
}

Normal Format - FromExpr:

{
  "$": "from",
  "Source": {
    "$": "table",
    "Type": "LiteOrm.Tests.Models.TestUser",
    "TableArgs": ["2024", "01"],
    "Alias": "u"
  },
  "Joins": []
}

2.7 WHERE Expression (WhereExpr)

Short Format:

{
  "$where": {"$from": {"$table": "LiteOrm.Tests.Models.TestUser"}},
  "Where": {
    "$and": [
      {"$": "==", "Left": {"#": "Status"}, "Right": {"@": "Pending"}},
      {"$": ">=", "Left": {"#": "TotalAmount"}, "Right": {"@": 300}}
    ]
  }
}

Normal Format:

{
  "$": "where",
  "Source": {
    "$": "from",
    "Source": {
      "$": "table",
      "Type": "LiteOrm.Tests.Models.TestUser"
    }
  },
  "Where": {
    "$": "and",
    "Items": [
      {"$": "logic", "Operator": 0, "Left": {"#": "Status"}, "Right": {"@": "Pending"}},
      {"$": "logic", "Operator": 3, "Left": {"#": "TotalAmount"}, "Right": {"@": 300}}
    ]
  }
}

2.8 ORDER BY Expression (OrderByExpr)

Short Format:

{
  "$orderby": {
    "$where": {"$from": {"$table": "LiteOrm.Tests.Models.TestUser"}}
  },
  "OrderBys": [
    {"Field": {"#": "TotalAmount"}, "Asc": false},
    {"Field": {"#": "CreatedTime"}, "Asc": false}
  ]
}

Normal Format:

{
  "$": "orderby",
  "Source": {...},
  "OrderBys": [
    {
      "$": "orderbyitem",
      "Field": {"$": "property", "PropertyName": "TotalAmount"},
      "Asc": false
    },
    {
      "$": "orderbyitem",
      "Field": {"$": "property", "PropertyName": "CreatedTime"},
      "Asc": false
    }
  ]
}

2.9 Section Expression (SectionExpr)

Short Format:

{
  "$section": {
    "$orderby": {...},
    "OrderBys": [
      {"Field": {"#": "CreatedTime"}, "Asc": false}
    ]
  },
  "Skip": 0,
  "Take": 10
}

3. Complete Query Example

Short Format

{
  "$section": {
    "$orderby": {
      "$where": {"$from": {"$table": "LiteOrm.Tests.Models.TestUser"}},
      "Where": {
        "$and": [
          {"$": "==", "Left": {"#": "Status"}, "Right": {"@": "Pending"}},
          {"$": ">=", "Left": {"#": "TotalAmount"}, "Right": {"@": 300}},
          {"$": "contains", "Left": {"#": "DepartmentName"}, "Right": {"@": "Operations"}}
        ]
      },
      "OrderBys": [
        {"Field": {"#": "TotalAmount"}, "Asc": false},
        {"Field": {"#": "CreatedTime"}, "Asc": false}
      ]
    }
  },
  "Skip": 0,
  "Take": 5
}

Normal Format

{
  "$": "section",
  "Source": {
    "$": "orderby",
    "Source": {
      "$": "where",
      "Source": {
        "$": "from",
        "Source": {
          "$": "table",
          "Type": "LiteOrm.Tests.Models.Order"
        }
      },
      "Where": {
        "$": "and",
        "Items": [
          {
            "$": "logic",
            "Operator": 0,
            "Left": {"$": "property", "PropertyName": "Status"},
            "Right": {"$": "value", "Value": "Pending", "IsConst": false}
          },
          {
            "$": "logic",
            "Operator": 3,
            "Left": {"$": "property", "PropertyName": "TotalAmount"},
            "Right": {"$": "value", "Value": 300, "IsConst": false}
          },
          {
            "$": "logic",
            "Operator": 11,
            "Left": {"$": "property", "PropertyName": "DepartmentName"},
            "Right": {"$": "value", "Value": "Operations", "IsConst": false}
          }
        ]
      }
    },
    "OrderBys": [
      {
        "$": "orderbyitem",
        "Field": {"$": "property", "PropertyName": "TotalAmount"},
        "Asc": false
      },
      {
        "$": "orderbyitem",
        "Field": {"$": "property", "PropertyName": "CreatedTime"},
        "Asc": false
      }
    ]
  },
  "Skip": 0,
  "Take": 5
}

Note:

4. Extra note on FunctionExpr

FunctionExpr is easy to document incorrectly because its short form is not $fn. The current implementation uses the func marker, then stores the function name as the property name.

Short Format

{
  "$": "func",
  "DateDiffDays": [
    {"#": "EndTime"},
    {"#": "StartTime"}
  ]
}

Normal Format

{
  "$": "func",
  "FunctionName": "DateDiffDays",
  "Args": [
    {"$": "property", "PropertyName": "EndTime"},
    {"$": "property", "PropertyName": "StartTime"}
  ]
}

Reading Tip