ent orm笔记4---Code Generation

全面揭秘 Go 语言超强 ORM 框架 Ent:高效构建数据库的终极武器! 阅读详情

在前面几篇文章中,我们经常使用的可能就是entc这个命令了,entc这个工具给带来了很多功能,这篇文章主要整理关于ent orm 中Code Generation

之前的例子中有个知识点少整理了,就是关于如果我们想要看orm在执行过程中详细原生sql语句是可以开启Debug看到的,代码如下:

client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/graph_traversal?parseTime=True",ent.Debug())

序言

Initialize A New Schema

通过类似如下命令可以生成Schema 模板:

entc init User Pet

init 将在ent/schema 目录下创建两个schema user.go 和 pet.go ,如果ent目录不存在,则会创建

Generate Assets

在添加了fields 和 edges 后,可以在项目的根目录运行entc generate 或者使用go generate 生成代码

go generate ./ent

Generate 命令生成以下内容:

  • 用于与graph 交互的Client 和Tx对象

  • schema 的CRUD生成器

  • 每个schema类型的Entity对象

  • 用于与构建交互的常量和断言

  • SQL方言的migrate 包

Version Compatibility Between entc And ent

这里主要是关于在项目中使用ent 的时候ent的版本要和entc的包的版本相同,并且项目中使用Go modules 进行包管理

Code Generation Options

要了解更多关于 codegen 选项的信息,entc generate -h :

generate go code for the schema directory

Usage:
  entc generate [flags] path

Examples:
  entc generate ./ent/schema
  entc generate github.com/a8m/x

Flags:
      --header string                           override codegen header
  -h, --help                                    help for generate
      --idtype [int int64 uint uint64 string]   type of the id field (default int)
      --storage string                          storage driver to support in codegen (default "sql")
      --target string                           target directory for codegen
      --template strings                        external templates to execute

Storage

entc 可以为 SQL 和 Gremlin 方言生成资产。

External Templates

接受要执行的外部 Go 模板。如果模板名称已经由 entc 定义,它将覆盖现有的名称。否则,它将把执行输出写入与模板同名的文件。Flag 格式支持如下文件、目录和 glob:

entc generate --template <dir-path> --template glob="path/to/*.tmpl" ./ent/schema

更多的信息和例子可以在外部模板文档中找到

Use entc As A Package

运行 entc 的另一个选项是将其作为一个包使用,如下所示:

package main

import (
    "log"

    "github.com/facebook/ent/entc"
    "github.com/facebook/ent/entc/gen"
    "github.com/facebook/ent/schema/field"
)

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Header: "// Your Custom Header",
        IDType: &field.TypeInfo{Type: field.TypeInt},
    })
    if err != nil {
        log.Fatal("running ent codegen:", err)
    }
}

Schema Description

如果想要得到我们定义的schema的描述信息,可以通过如下命令:

entc describe ./ent/schema

以之前的例子中执行效果如下:

User:
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        | Field |  Type  | Unique | Optional | Nillable | Default | UpdateDefault | Immutable |       StructTag       | Validators |
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        | id    | <nil>  | false  | false    | false    | false   | false         | false     | json:"id,omitempty"   |          0 |
        | name  | string | false  | false    | false    | false   | false         | false     | json:"name,omitempty" |          0 |
        +-------+--------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
        +-----------+------+---------+-----------+----------+--------+----------+
        |   Edge    | Type | Inverse |  BackRef  | Relation | Unique | Optional |
        +-----------+------+---------+-----------+----------+--------+----------+
        | followers | User | true    | following | M2M      | false  | true     |
        | following | User | false   |           | M2M      | false  | true     |
        +-----------+------+---------+-----------+----------+--------+----------+

CRUD API

Create A New Client

「MySQL」

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    client, err := ent.Open("mysql", "<user>:<pass>@tcp(<host>:<port>)/<database>?parseTime=True")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

「PostgreSQL」

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/lib/pq"
)

func main() {
    client, err := ent.Open("postgres","host=<host> port=<port> user=<user> dbname=<database> password=<pass>")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

「SQLite」

package main

import (
    "log"

    "<project>/ent"

    _ "github.com/mattn/go-sqlite3"
)

func main() {
    client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}

「Gremlin (AWS Neptune)」

package main

import (
    "log"

    "<project>/ent"
)

func main() {
    client, err := ent.Open("gremlin", "http://localhost:8182")
    if err != nil {
        log.Fatal(err)
    }
}

Create An Entity

「Save」 a user.

a8m, err := client.User.    // UserClient.
    Create().               // User create builder.
    SetName("a8m").         // Set field value.
    SetNillableAge(age).    // Avoid nil checks.
    AddGroups(g1, g2).      // Add many edges.
    SetSpouse(nati).        // Set unique edge.
    Save(ctx)               // Create and return.

「SaveX」 a pet; Unlike 「Save」, 「SaveX」 panics if an error occurs.

pedro := client.Pet.    // PetClient.
    Create().           // Pet create builder.
    SetName("pedro").   // Set field value.
    SetOwner(a8m).      // Set owner (unique edge).
    SaveX(ctx)          // Create and return.

Create Many

「Save」 a bulk of pets

names := []string{"pedro", "xabi", "layla"}
bulk := make([]*ent.PetCreate, len(names))
for i, name := range names {
    bulk[i] = client.Pet.Create().SetName(name).SetOwner(a8m)
}
pets, err := client.Pet.CreateBulk(bulk...).Save(ctx)

Update One

更新一个从数据库返回的entity

a8m, err = a8m.Update().    // User update builder.
    RemoveGroup(g2).        // Remove specific edge.
    ClearCard().            // Clear unique edge.
    SetAge(30).             // Set field value
    Save(ctx)               // Save and return.

Update By ID

pedro, err := client.Pet.   // PetClient.
    UpdateOneID(id).        // Pet update builder.
    SetName("pedro").       // Set field name.
    SetOwnerID(owner).      // Set unique edge, using id.
    Save(ctx)               // Save and return.

Update Many

以断言进行过滤

n, err := client.User.          // UserClient.
    Update().                   // Pet update builder.
    Where(                      //
        user.Or(                // (age >= 30 OR name = "bar") 
            user.AgeEQ(30),     //
            user.Name("bar"),   // AND
        ),                      //  
        user.HasFollowers(),    // UserHasFollowers()  
    ).                          //
    SetName("foo").             // Set field name.
    Save(ctx)                   // exec and return.

通过edge 断言进行查询

n, err := client.User.          // UserClient.
    Update().                   // Pet update builder.
    Where(                      // 
        user.HasFriendsWith(    // UserHasFriendsWith (
            user.Or(            //   age = 20
                user.Age(20),   //      OR
                user.Age(30),   //   age = 30
            )                   // )
        ),                      //
    ).                          //
    SetName("a8m").             // Set field name.
    Save(ctx)                   // exec and return.

Query The Graph

获取所有用户的关注者

users, err := client.User.      // UserClient.
    Query().                    // User query builder.
    Where(user.HasFollowers()). // filter only users with followers.
    All(ctx)                    // query and return.

获取特定用户的所有跟随者; 从graph中的一个节点开始遍历

users, err := a8m.
    QueryFollowers().
    All(ctx)

获取所有宠物的名字

names, err := client.Pet.
    Query().
    Select(pet.FieldName).
    Strings(ctx)

获取所有宠物的名字和年龄

var v []struct {
    Age  int    `json:"age"`
    Name string `json:"name"`
}
err := client.Pet.
    Query().
    Select(pet.FieldAge, pet.FieldName).
    Scan(ctx, &v)
if err != nil {
    log.Fatal(err)
}

Delete One

这个用于如果我们已经通过client查询到了一个entity,然后想要删除这条记录:

err := client.User.
    DeleteOne(a8m).
    Exec(ctx)

Delete by ID.

err := client.User.
    DeleteOneID(id).
    Exec(ctx)

Delete Many

使用断言进行删除

err := client.File.
    Delete().
    Where(file.UpdatedAtLT(date))
    Exec(ctx)

Mutation

通过 entc init 生成的每个schema 都有自己的mutaion,例如我们通过 entc init User Pet, 在通过go generate ./ent 生成的代码中有 ent/mutation.go

在该文件中定义了:

.....
// UserMutation represents an operation that mutate the Users
// nodes in the graph.
type UserMutation struct {
 config
 op            Op
 typ           string
 id            *int
 name          *string
 age           *int
 addage        *int
 clearedFields map[string]struct{}
 done          bool
 oldValue      func(context.Context) (*User, error)
}

.....

// PetMutation represents an operation that mutate the Pets
// nodes in the graph.
type PetMutation struct {
 config
 op            Op
 typ           string
 id            *int
 name          *string
 age           *int
 addage        *int
 clearedFields map[string]struct{}
 done          bool
 oldValue      func(context.Context) (*Pet, error)
}

例如,所有的User builders都共享相同的UserMutaion 对象,左右的builder 类型都继承通用的ent.Mutation接口.

这里所说的 user builders,拿User schema来说指的是UserCreate、UserDelete、UserQuery、UserUpdate 对象,go generate 生成的代码中,我们可以到

./ent/user_create.go、./ent/user_delete.go、./ent/user_query.go、./ent/user_update.go文件中看到如下定义:

// ./ent/user_create.go

// UserCreate is the builder for creating a User entity.
type UserCreate struct {
 config
 mutation *UserMutation
 hooks    []Hook
}


//./ent/user_delete.go
// UserDelete is the builder for deleting a User entity.
type UserDelete struct {
 config
 hooks      []Hook
 mutation   *UserMutation
 predicates []predicate.User
}

// ./ent/user_query.go
// UserQuery is the builder for querying User entities.
type UserQuery struct {
 config
 limit      *int
 offset     *int
 order      []OrderFunc
 unique     []string
 predicates []predicate.User
 // intermediate query (i.e. traversal path).
 sql  *sql.Selector
 path func(context.Context) (*sql.Selector, error)
}

// ./ent/user_update.go
// UserUpdate is the builder for updating User entities.
type UserUpdate struct {
 config
 hooks      []Hook
 mutation   *UserMutation
 predicates []predicate.User
}

在下面的例子中,ent.UserCreate 和 ent.UserUpdate 都使用一个通用的方法对age 和name 列进行操作:

package main

import (
   "context"
   "log"

   _ "github.com/go-sql-driver/mysql"
   "github.com/peanut-cc/ent_orm_notes/aboutMutaion/ent"
)

func main() {
   client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/aboutMutaion?parseTime=True")
   if err != nil {
      log.Fatal(err)
   }
   defer client.Close()
   ctx := context.Background()
   // run the auto migration tool
   if err := client.Schema.Create(ctx); err != nil {
      log.Fatalf("failed creating schema resources:%v", err)
   }
   Do(ctx, client)
}

func Do(ctx context.Context, client *ent.Client) {
   creator := client.User.Create()
   SetAgeName(creator.Mutation())
   creator.SaveX(ctx)
   updater := client.User.UpdateOneID(1)
   SetAgeName(updater.Mutation())
   updater.SaveX(ctx)
}

// SetAgeName sets the age and the name for any mutation.
func SetAgeName(m *ent.UserMutation) {
   m.SetAge(32)
   m.SetName("Ariel")
}

在某些情况下,你希望对多个不同的类型应用同一个方法,对于这种情况,要么使用通用的ent.Mutation 接口,或者自己实现一个接口,代码如下:

func Do2(ctx context.Context, client *ent.Client) {
   creator1 := client.User.Create().SetAge(18)
   SetName(creator1.Mutation(), "a8m")
   creator1.SaveX(ctx)
   creator2 := client.Pet.Create().SetAge(16)
   SetName(creator2.Mutation(), "pedro")
   creator2.SaveX(ctx)
}

// SetNamer wraps the 2 methods for getting
// and setting the "name" field in mutations.
type SetNamer interface {
   SetName(string)
   Name() (string, bool)
}

func SetName(m SetNamer, name string) {
   if _, exist := m.Name(); !exist {
      m.SetName(name)
   }
}

Graph Traversal

在这个部分的例子中会使用如下的Graph

er-traversal-graph

er-traversal-graph-gopher

上面的遍历从一个 Group 实体开始,继续到它的 admin (edge) ,继续到它的朋友(edge) ,获取他们的宠物(edge) ,获取每个宠物的朋友(edge) ,并请求它们的主人

func Traverse(ctx context.Context, client *ent.Client) error {
    owner, err := client.Group.         // GroupClient.
        Query().                        // Query builder.
        Where(group.Name("Github")).    // Filter only Github group (only 1).
        QueryAdmin().                   // Getting Dan.
        QueryFriends().                 // Getting Dan's friends: [Ariel].
        QueryPets().                    // Their pets: [Pedro, Xabi].
        QueryFriends().                 // Pedro's friends: [Coco], Xabi's friends: [].
        QueryOwner().                   // Coco's owner: Alex.
        Only(ctx)                       // Expect only one entity to return in the query.
    if err != nil {
        return fmt.Errorf("failed querying the owner: %v", err)
    }
    fmt.Println(owner)
    // Output:
    // User(id=3, age=37, name=Alex)
    return nil
}

下面的遍历如何?

er-traversal-graph-gopher-query

我们希望得到所有宠物(entities)的所有者(edge)是朋友(edge)的一些群管理员(edge)。

func Traverse2(ctx context.Context, client *ent.Client) error {
 pets, err := client.Pet.
  Query().
  Where(
   pet.HasOwnerWith(
    user.HasFriendsWith(
     user.HasManage(),
    ),
   ),
  ).
  All(ctx)
 if err != nil {
  return fmt.Errorf("failed querying the pets: %v", err)
 }
 fmt.Println(pets)
 // Output:
 // [Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
 return nil
}

上面的查询中,查询所有的宠物,条件是: 宠物要有主人,同时宠物的主人是要有朋友,同时该主人还要属于管理员

Eager Loading

ent 支持通过它们的edges 查询,并将关联的entities 添加到返回的对象中

通过下面的例子理解:

er-group-users

查询上面关系中所有用户和它们的宠物,代码如下:

func edgerLoading(ctx context.Context, client *ent.Client) {
   users, err := client.User.Query().WithPets().All(ctx)
   if err != nil {
      log.Fatalf("user query failed:%v", err)
   }
   log.Println(users)
   for _, u := range users {
      for _, p := range u.Edges.Pets {
         log.Printf("user (%v) -- > Pet (%v)\n", u.Name, p.Name)
      }
   }

}

完整的代码在:https://github.com/peanut-cc/ent_orm_notes/graph_traversal

查询的结果如下:

2020/09/01 20:09:07 [User(id=1, age=29, name=Dan) User(id=2, age=30, name=Ariel) User(id=3, age=37, name=Alex) User(id=4, age=18, name=peanut)]
2020/09/01 20:09:07 user (Ariel) -- > Pet (Pedro)
2020/09/01 20:09:07 user (Ariel) -- > Pet (Xabi)
2020/09/01 20:09:07 user (Alex) -- > Pet (Coco)

预加载允许查询多个关联,包括嵌套关联,还可以过滤,排序或限制查询结果,例如:

func edgerLoading2(ctx context.Context, client *ent.Client) {
   users, err := client.User.
      Query().
      Where(
         user.AgeGT(18),
      ).
      WithPets().
      WithGroups(func(q *ent.GroupQuery) {
         q.Limit(5)
         q.WithUsers().Limit(5)
      }).All(ctx)
   if err != nil {
      log.Fatalf("user query failed:%v", err)
   }
   log.Println(users)
   for _, u := range users {
      for _, p := range u.Edges.Pets {
         log.Printf("user (%v) --> Pet (%v)\n", u.Name, p.Name)
      }
      for _, g := range u.Edges.Groups {
         log.Printf("user (%v) -- Group (%v)\n", u.Name, g.Name)
      }
   }

}

每个query-builder都有一个方法列表,其形式为 With<E>(...func(<N>Query))

<E>代表边缘名称(像WithGroups) ,< N> 代表边缘类型(像GroupQuery)。

注意,只有 SQL 方言支持这个特性

Aggregation

Group By

按所有用户的姓名和年龄字段分组,并计算其总年龄。

package main

import (
 "context"
 "log"

 "github.com/peanut-cc/ent_orm_notes/groupBy/ent/user"

 _ "github.com/go-sql-driver/mysql"

 "github.com/peanut-cc/ent_orm_notes/groupBy/ent"
)

func main() {
 client, err := ent.Open("mysql", "root:123456@tcp(10.211.55.3:3306)/groupBy?parseTime=True",
  ent.Debug())
 if err != nil {
  log.Fatal(err)
 }
 defer client.Close()
 ctx := context.Background()
 // run the auto migration tool
 if err := client.Schema.Create(ctx); err != nil {
  log.Fatalf("failed creating schema resources:%v", err)
 }
 GenData(ctx, client)
 Do(ctx, client)

}

func GenData(ctx context.Context, client *ent.Client) {
 client.User.Create().SetName("peanut").SetAge(18).SaveX(ctx)
 client.User.Create().SetName("jack").SetAge(20).SaveX(ctx)
 client.User.Create().SetName("steve").SetAge(22).SaveX(ctx)
 client.User.Create().SetName("peanut-cc").SetAge(18).SaveX(ctx)
 client.User.Create().SetName("jack-dd").SetAge(18).SaveX(ctx)
}

func Do(ctx context.Context, client *ent.Client) {
 var v []struct {
  Name  string `json:"name"`
  Age   int    `json:"age"`
  Sum   int    `json:"sum"`
  Count int    `json:"count"`
 }
 client.User.
  Query().
  GroupBy(
   user.FieldName, user.FieldAge,
  ).
  Aggregate(
   ent.Count(),
   ent.Sum(user.FieldAge),
  ).
  ScanX(ctx, &v)
 log.Println(v)

}

按一个字段分组,例子如下:

func Do2(ctx context.Context, client *ent.Client) {
 names := client.User.Query().GroupBy(user.FieldName).StringsX(ctx)
 log.Println(names)
}

Predicates

Field Predicates

  • Bool:

    • =, !=

  • Numberic:

    • =, !=, >, <, >=, <=,

    • IN, NOT IN

  • Time:

    • =, !=, >, <, >=, <=

    • IN, NOT IN

  • String:

    • =, !=, >, <, >=, <=

    • IN, NOT IN

    • Contains, HasPrefix, HasSuffix

    • ContainsFold, EqualFold (「SQL」 specific)

  • Optional fields:

    • IsNil, NotNil

Edge Predicates

「HasEdge」 例如,查询所有宠物的所有者,使用:

 client.Pet.
      Query().
      Where(pet.HasOwner()).
      All(ctx)

「HasEdgeWith」

 client.Pet.
      Query().
      Where(pet.HasOwnerWith(user.Name("a8m"))).
      All(ctx)

Negation (NOT)

client.Pet.
    Query().
    Where(pet.Not(pet.NameHasPrefix("Ari"))).
    All(ctx)

Disjunction (OR)

client.Pet.
    Query().
    Where(
        pet.Or(
            pet.HasOwner(),
            pet.Not(pet.HasFriends()),
        )
    ).
    All(ctx)

Conjunction (AND)

client.Pet.
    Query().
    Where(
        pet.And(
            pet.HasOwner(),
            pet.Not(pet.HasFriends()),
        )
    ).
    All(ctx)

Custom Predicates

如果想编写自己的特定方言的逻辑,Custom predicates可能很有用。

pets := client.Pet.
    Query().
    Where(predicate.Pet(func(s *sql.Selector) {
        s.Where(sql.InInts(pet.OwnerColumn, 1, 2, 3))
    })).
    AllX(ctx)

Paging And Ordering

Limit

将查询结果限制为 n 个实体。

users, err := client.User.
    Query().
    Limit(n).
    All(ctx)

Offset

设置从查询返回的第一个最大数量。

users, err := client.User.
    Query().
    Offset(10).
    All(ctx)

Ordering

Order 返回按一个或多个字段的值排序的实体。

users, err := client.User.Query().
    Order(ent.Asc(user.FieldName)).
    All(ctx)

延伸阅读

  • https://entgo.io/

代码生成(Code Generation) 表达式编译 代码生成(Code Generation)技术广泛应用于现代的数据系统中。代码生成是将用户输入的表达式、查询、存储过程等现场编译成二进制代码再执行,相比解释执行的方式,运行效率要高得多。尤其是对于计算密集型查询、或频繁重复使用的计算过程,运用代码生成技术能达到数十倍的性能提升。 当我们谈论代码生成时我们在谈论什么 很多大数据产品都将代码生成技术作为卖点,然而事实上他们往往谈论的不是一件事情。比如,之前就有人提问:Spark 1.x 就已经有代码生成技术,为什么 Spark 2.0 又把代码生成吹了一番?其中 阅读详情

相关推荐

代码生成 (Code Generation)

1. 背景介绍 1.1 问题由来 随着人工智能技术的快速发展,代码生成 (Code Generation) 成为了自动程序生成、程序维护、代码智能推荐、辅助编程等一系列应用的重要方向。传统的代码生成依赖于开发者经验和手工编码,耗时耗力,且容易出错。而使用自动化代码生成技术,不仅能够大幅度提升代码编写效率,还

欢迎来到我的优快云空间!这里聚焦AI大模型应用实战,分享前沿技术、实战案例与开发经验。 1984

Golang-Ent ORM框架

面向对象编程和关系型数据库,都是目前最流行的技术,但是它们的模型是不一样的。面向对象编程把所有实体看成对象(object),关系型数据库则是采用实体之间的关系(relation)连接数据。很早就有人提出,关系也可以用对象表达,这样的话,就能使用面向对象编程,来操作关系型数据库。简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。ORM 把数据库映射成对象。

Ch3nnn的博客 2932

探索Vortex开源GPGPU:RISC-V SIMT架构(4-1),Execute SFU(1)

本文详细分析了Vortex RISC-V内核6级流水线中Execute阶段的SFU(特殊功能单元)模块。重点介绍了SFU的数据流结构,包含dispatch_unit、pe_switch、csr_unit、wctl_unit和gather_unit五个子模块。文章深入解析了warp控制指令wspawn和tmc的实现机制:wspawn用于激活指定数量的warp并设置新PC值,tmc则用于控制线程掩码和warp状态。通过C代码和汇编指令的对照分析,阐明了这些指令在并行计算中的关键作用,包括线程激活、状态切换和执行

weixin_55313207的博客 1363

go语言ORM框架ent使用教程

ent是什么 ent是一个简单而又功能强大的Go语言实体框架,ent易于构建和维护应用程序与大数据模型。 简而言之,ent是一款便于操作的orm框架 installation go get entgo.io/ent/cmd/ent 使用 创建schema 在连接ent之前,我们首先需要创建schema,创建schema的作用类似django创建model,规定数据表字段,定义表名等 cli创建model模板命令 ent init --target <target dirpath> <Mod

爱吃回锅肉的胖子 1万+

数字孪生实战:如何用Blender+Unity快速搭建未来工厂3D模型(附资源包)

本文提供了一套利用Blender进行三维建模,再结合Unity构建虚拟仿真环境的实用方案,旨在帮助中小型制造企业低成本、高效率地搭建未来工厂数字孪生原型系统。文章详细介绍了从数据规划、模型优化到场景构建、逻辑仿真与数据对接的全流程,并附有资源包,助力技术团队快速实现从静态展示到动态交互的数字孪生应用。

weixin_29191669的博客 338

零基础小白Coze知识普及【新手必备资料!!】

AI智能体|扣子(Coze)工作流搭建【零基础小白Coze知识普及】 1、领取100+工作流源码!复制到扣子即可直接使用 2、AI认知+9节商业智能体拆解 3、500+各行业高质量提示词 4、超低价格使用即梦文生图图生视频和banana生图

Zhima0522的博客 3250

ent4/ent比较分析:与其他ORM框架的优劣对比

在现代软件开发中,对象关系映射(ORM,Object-Relational Mapping)框架扮演着至关重要的角色,它能够简化数据访问层的开发,提高开发效率,同时减少手动编写SQL的错误。ent4/ent作为Go语言生态中一款新兴的ORM框架,以其独特的设计理念和强大的功能受到了广泛关注。本文将从多个维度对ent4/ent与其他主流ORM框架进行深入比较,分析其优势与不足,帮助开发者做出更合适的...

gitblog_00345的博客 462

Jetson Orin边缘语音AI实战:用Riva ASR/TTS + Llama 2打造离线智能语音助手

本文详细介绍了如何利用NVIDIA Jetson Orin的边缘计算能力,结合Riva ASR/TTS语音引擎和Llama 2大语言模型,构建完全离线的智能语音助手。通过硬件优化、量化部署和性能调优,实现在网络不稳定环境下的高效语音交互,适用于智能家居、车载系统等场景。

weixin_29053383的博客 242

搞懂常见Go ORM系列-Ent框架详解

Ent 是一个用于 Go 语言的 ORM(对象关系映射)框架它的最大特点是通过代码生成的方式,提供类型安全的数据库访问能力在使用 Ent 时,首先需要定义 schema,然后通过工具生成数据库访问代码,这样不仅提高了开发效率,还能避免常见的运行时错误Ent 支持多种关系型数据库,包括 MySQL、PostgreSQL、SQLite 和 Microsoft SQL Server,并且对数据库结构和关系的支持非常全面在使用 Ent 时,开发者需要先定义 schema,这是 Ent 中模型的基础。

2401_89221445的博客 2279

嵌入式NTC温度解算库:Steinhart-Hart定点实现与硬件解耦设计

NTC热敏电阻是嵌入式系统中最常用的模拟温度传感器,其阻值-温度关系高度非线性,需依赖Steinhart-Hart方程实现高精度转换。该方程通过三参数对数多项式建模,理论上可将误差控制在±0.1°C以内,但直接移植到MCU面临浮点开销大、定点溢出、系数精度损失等工程瓶颈。为此,归一化处理(ln(R/R₂₅))、Q24.8定点运算、查表+插值对数计算等优化技术成为资源受限场景下的关键技术路径。其核心价值在于将ADC采样与温度解算彻底解耦,适配各类HAL/裸机/RTOS环境,广泛应用于电池管理、工业PLC、Io

weixin_35756624的博客 647

Oracle19c SYSAUX表空间爆满?手把手教你清理SM/ADVISOR和AUDSYS占用(附完整SQL)

本文详细解析了Oracle19c中SYSAUX表空间爆满的常见原因及解决方案,重点针对SM/ADVISOR和AUDSYS组件的空间占用问题提供了完整的SQL清理脚本。通过诊断查询、空间清理和预防性维护策略,帮助DBA有效管理SYSAUX表空间,确保数据库稳定运行。

weixin_28338005的博客 236

Ent ORM 实战:类型安全的数据库设计艺术

import ("fmt"// User 定义用户实体ent.Schema// Fields 定义用户字段// 基础信息Unique(),// 角色与状态// 编译期枚举验证switch s {return nildefault:}),// 财务字段:使用 decimal 确保精度// 并发控制Comment("用户级最大并发请求数"),// 安全字段// 通知设置// 时间戳// Edges 定义关系// 一个用户拥有多个 API Key。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 479

用MCP扩展Cursor的5种神奇用法:从文件操作到网页抓取实战

本文深入探讨了如何利用MCP(Model Context Protocol)扩展Cursor AI编程助手,解锁五种高效实用场景。从文件系统操作、网页内容抓取,到数据库查询、Figma设计稿对接,乃至构建自定义MCP服务器,文章通过实战案例展示了如何将Cursor从代码编辑器升级为能理解并操作工作环境的智能助手,显著提升开发效率与自动化水平。

weixin_29231027的博客 315

终极指南:如何使用Pagoda快速构建Go全栈Web应用与动态管理面板

Pagoda是一个基于Go语言的快速、简易全栈Web开发启动工具包,它提供了完整的Web框架功能和管理面板,帮助开发者轻松构建现代Web应用。本文将深入解析Pagoda的核心功能、Ent ORM集成以及动态管理面板的实战应用,为初学者和普通用户提供全面的使用指南。 ## 🚀 为什么选择Pagoda?核心优势解析 Pagoda并非传统意义上的框架,而是一个功能完备的启动工具包,它建立在一系列成

gitblog_00197的博客 963

USB 网卡——RNDIS 控制消息流程

在其控制端点上获取控制消息时,设备必须在通信类接口的中断 IN 端点上返回通知,每当设备可以返回控制消息时,主机就会轮询该通知。需要注意的是,如果设备由于某种原因收到GET_ENCAPSULATED_RESPONSE,并且无法使用控制端点上的有效数据做出响应,则应返回设置为 0x00 的单字节数据包,而不是 stall 控制端点。下表中定义了此传输。收到 RESPONSE_AVAILABLE 通知后,主机使用下表中定义的GET_ENCAPSULATED_RESPONSE 传输从控制端点读取控制消息。

tyustli 371

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ent orm笔记1---快速尝鲜

前几天看到消息Facebook孵化的ORM ent转为正式项目,出去好奇,简单体验了一下,使用上自己感觉比GORM好用,于是打算把官方的文档进行整理,也算是学习一下如何使用。安装ent ...

后场技术 1404

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【go】ent操作之CRUD与联表查询

举例,一个用户可以有多个订单的场景下的模型定义。

微雨停了的博客 2144

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

超强ent4/ent框架:代码生成驱动的静态类型ORM新范式

你还在为手写SQL、处理复杂数据关系而烦恼吗?ent4/ent框架通过代码生成和静态类型检查,让数据访问层开发效率提升10倍!本文将带你快速掌握这一革命性ORM工具的核心优势、5分钟上手流程及实战技巧,让你彻底告别重复劳动,专注业务逻辑开发。 ## 核心特性一览 ent4/ent作为Go语言生态中领先的ORM框架,凭借代码生成驱动和静态类型安全两大核心优势,彻底改变了传统ORM的开发模式。以下...

gitblog_00215的博客 703

05 ORM

六、模型层(ORM) Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。 O是object,也就类对象的意思。 R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思。 M是mapping,是映射的意思。 映射: 类:sql语句table表 类成员变量:table表中的字段、类型和约束 类对象:sql表的表记录 ORM的优点 数据模型类都在一个地方定义,更容易更新和维护,也利于重用代

从不喝奶茶的博客 1592

MDSF:代码生成(Code Generation)介绍

在实现模型驱动开发中,我们可以解释模型直接运行在领域框架之上,也可以把模型通过代码生成技术转换成代码之后编译运行在框架之上。这两种方式都有利弊,可以搭配使用,在OpenExpessApp中将采用这两种方法,类库通过代码生成,UI等元模型通过框架解释执行。由于代码生成是MDD中很重要的一项技术,所以本篇我将介绍一下代码生成相关的知识。 模型驱动中的代码生成 在EMF中,Metamodel为E...

weixin_34375054的博客 807

Simulink自动代码生成:Code Generation配置(一)

  本节我们来学习Code Generation相关内容,可以说Code Generation配置是自动代码生成最重要的配置,虽然很多情况下很多配置不需要改动,但是明白它们是如何影响代码生成的对我们项目开发还是相当必要的,以便我们在需要更改代码配置的时候清除改哪里。接下来我将分几节对该部分内容进行讲解,主要是写一篇长文章需要耗费的时间太长了,博主还要上班实在没时间一次写那么多。 目录一. 打开Code Generation二. 对Code Generation进行配置三. 总结 一. 打开Code Gene

freedom_qqcom的博客 3万+

ent orm笔记2---schema使用(下)

Indexes 索引在前两篇的文章中,其实对于索引也有一些使用, 这里来详细看一下关于索引的使用Indexes方法可以在一个或者多个字段上设置索引,以提高数据检索的速度或者定义数据的唯一...

后场技术 769

ent orm笔记2---schema使用(上)

在上一篇关于快速使用ent orm的笔记中,我们在最开始使用entc init User 创建schema,在ent orm 中的schema 其实就是数据库模型,在schema中我们可...

后场技术 1659

【GoCN酷Go推荐】简单强大ORM框架entgo

简介ent 是一个简单而又强大的Go实体框架,便于构建和使用大型数据模型时能够遵循以下原则:简单地使用数据库结构作为图结构。使用Go代码定义结构。基于代码生成的静态类型。容易地进行数据库查...

Go中国 3280
上一篇: ent orm笔记2---schema使用(下)
下一篇: ClickHouse性能关键性指标有哪些?
后场技术
博客等级 码龄11年 156粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值