[{"data":1,"prerenderedAt":569},["ShallowReactive",2],{"news-item-\u002Fvi\u002Fnews\u002Ftypeorm":3},{"id":4,"title":5,"body":6,"category":556,"created by":557,"date":558,"description":559,"extension":560,"meta":561,"navigation":562,"path":563,"sections":564,"seo":565,"stem":566,"thumbnail":567,"__hash__":568},"content_vi\u002Fvi\u002Fnews\u002Ftypeorm.md","TypeORM và Query Builder trong TypeORM",{"type":7,"value":8,"toc":539},"minimark",[9,17,21,24,29,32,35,39,42,45,48,51,55,58,61,64,67,70,73,79,82,88,91,102,108,111,117,123,126,132,138,141,147,153,159,161,167,173,179,181,187,193,199,201,207,213,219,221,227,233,236,239,244,250,252,258,263,269,272,278,283,289,294,300,305,311,316,319,322,328,334,337,343,347,353,355,360,364,370,372,377,381,387,389,394,398,404,406,411,415,421,423,428,433,439,445,449,455,457,463,467,473,475,481,485,491,495,501,505,511,515,518,521,524,527,531],[10,11,13],"h2",{"id":12},"giới-thiệu",[14,15,16],"strong",{},"Giới thiệu",[18,19,20],"p",{},"TypeORM là một ORM có thể chạy trong các nền tảng NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo và Electron và có thể được sử dụng với TypeScript và JavaScript (ES5, ES6, ES7, ES8). Mục tiêu của nó là luôn hỗ trợ các tính năng JavaScript mới nhất và cung cấp các tính năng bổ sung giúp bạn phát triển bất kỳ loại ứng dụng nào sử dụng cơ sở dữ liệu - từ các ứng dụng nhỏ với một vài bảng đến các ứng dụng doanh nghiệp quy mô lớn với nhiều cơ sở dữ liệu.",[18,22,23],{},"ORM là một loại công cụ ánh xạ các thực thể với các bảng cơ sở dữ liệu. ORM cung cấp đơn giản hóa quá trình phát triển bằng cách tự động hóa chuyển đổi đối tượng sang bảng và từ bảng sang đối tượng.",[25,26,28],"h3",{"id":27},"tổng-quan","Tổng quan",[18,30,31],{},"TypeORM là một thư viện Object Relational Mapper chạy trong node.js và được viết bằng TypeScript. TypeScript là một cải tiến đối với JavaScript với kiểu gõ tùy chọn. TypeScript là một ngôn ngữ biên dịch. Nó không được diễn giải tại thời điểm chạy run-time. Trình biên dịch TypeScript biên dịch file TypeScript (.ts) thành file JavaScript (.js).",[18,33,34],{},"TypeORM hỗ trợ nhiều cơ sở dữ liệu như MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana và WebSQL. TypeORM là ORM dễ sử dụng để tạo mới ứng dụng kết nối với cơ sở dữ liệu. Chức năng TypeORM là các khái niệm dành riêng cho RDBMS.",[25,36,38],{"id":37},"đặc-điểm-của-typeorm","Đặc điểm của TypeORM",[18,40,41],{},"Tự động tạo các lược đồ bảng cơ sở dữ liệu dựa trên các mô hình của bạn",[18,43,44],{},"Dễ dàng chèn, cập nhật và xóa đối tượng trong cơ sở dữ liệu",[18,46,47],{},"Tạo ánh xạ (một-một, một-nhiều và nhiều-nhiều) giữa các bảng",[18,49,50],{},"Cung cấp các lệnh CLI đơn giản",[25,52,54],{"id":53},"lợi-ích-của-typeorm","Lợi ích của TypeORM",[18,56,57],{},"TypeORM rất dễ sử dụng ORM framework với coding đơn giản. Nó có những lợi ích sau:",[18,59,60],{},"1. Các ứng dụng chất lượng cao và được ghép nối lỏng lẻo",[18,62,63],{},"2. Các ứng dụng có thể mở rộng",[18,65,66],{},"3. Dễ dàng tích hợp với các modules khác",[18,68,69],{},"4. Hoàn toàn phù hợp với mọi kiến trúc từ ứng dụng nhỏ đến ứng dụng doanh nghiệp",[18,71,72],{},"Trong typeorm có rất nhiều tính năng nhưng trong blog này mình sẽ viết về cách sử dụng query builder của typeorm với typescript.",[10,74,76],{"id":75},"query-builder",[14,77,78],{},"Query Builder",[18,80,81],{},"Query builder được sử dụng để xây dựng các truy vấn SQL phức tạp một cách dễ dàng. Nó được khởi tạo từ phương thức Connection.",[25,83,85],{"id":84},"connection",[14,86,87],{},"Connection",[18,89,90],{},"Hãy xem xét một ví dụ đơn giản về cách sử dụng QueryBuilder bằng phương thức kết nối:",[92,93,98],"pre",{"className":94,"code":96,"language":97},[95],"language-text","import {getConnection} from \"typeorm\";\n\nconst user = await getConnection()\n.createQueryBuilder()\n.from(\"user\", \"user\")\n.select(\"user\")\n.where(\"user.id = :id\", { id: 1 })\n.getOne();\n","text",[99,100,96],"code",{"__ignoreMap":101},"",[25,103,105],{"id":104},"repository",[14,106,107],{},"Repository",[18,109,110],{},"Chúng ta có thể sử dụng repository  để tạo trình tạo truy vấn. Nó được mô tả dưới đây,",[92,112,115],{"className":113,"code":114,"language":97},[95],"import {getRepository} from \"typeorm\"; \nconst user = await getRepository(User)\n.createQueryBuilder(\"user\")\n.where(\"user.id = :id\", { id: 1 }) \n.getOne();\n",[99,116,114],{"__ignoreMap":101},[25,118,120],{"id":119},"adding-expression-use-getconnection-no-model-needed",[14,121,122],{},"Adding expression use getConnection (no model needed)",[18,124,125],{},"table user: id, name, age",[18,127,128,131],{},[14,129,130],{},"where"," được sử dụng để lọc các bản ghi nếu điều kiện được khớp.",[92,133,136],{"className":134,"code":135,"language":97},[95],"getConnection().createQueryBuilder().from(\"user\", \"user\").select(\"user\") .where(\"user.id = :id\", { id: 1 }) .getRawOne();\n",[99,137,135],{"__ignoreMap":101},[18,139,140],{},"Truy vấn này tương đương với:",[92,142,145],{"className":143,"code":144,"language":97},[95],"select * from user where user.id=1;\n",[99,146,144],{"__ignoreMap":101},[18,148,149,152],{},[14,150,151],{},"orderBy"," được sử dụng để sắp xếp các bản ghi dựa trên trường",[92,154,157],{"className":155,"code":156,"language":97},[95],"getConnection().createQueryBuilder().from(\"user\", \"user\").orderBy(\"user.name\");\n",[99,158,156],{"__ignoreMap":101},[18,160,140],{},[92,162,165],{"className":163,"code":164,"language":97},[95],"select * from user order by user.name;\n",[99,166,164],{"__ignoreMap":101},[18,168,169,172],{},[14,170,171],{},"groupBy",": Nó được sử dụng để nhóm các bản ghi dựa trên cột được chỉ định.",[92,174,177],{"className":175,"code":176,"language":97},[95],"getConnection().createQueryBuilder().from(\"user\", \"user\").groupBy(\"user.id\")\n",[99,178,176],{"__ignoreMap":101},[18,180,140],{},[92,182,185],{"className":183,"code":184,"language":97},[95],"select * from user group by user.id; \n",[99,186,184],{"__ignoreMap":101},[18,188,189,192],{},[14,190,191],{},"limit",": được sử dụng để giới hạn việc chọn rows.",[92,194,197],{"className":195,"code":196,"language":97},[95],"getConnection().createQueryBuilder().from(\"user\", \"user\").limit(5);\n",[99,198,196],{"__ignoreMap":101},[18,200,140],{},[92,202,205],{"className":203,"code":204,"language":97},[95],"select * from user limit 5; \n",[99,206,204],{"__ignoreMap":101},[18,208,209,212],{},[14,210,211],{},"offset"," được sử dụng để chỉ định, có bao nhiêu rows để bỏ qua kết quả.",[92,214,217],{"className":215,"code":216,"language":97},[95],"getConnection().createQueryBuilder().from(\"user\", \"user\").offset(5);\n",[99,218,216],{"__ignoreMap":101},[18,220,140],{},[92,222,225],{"className":223,"code":224,"language":97},[95],"select * from user offset 5;\n",[99,226,224],{"__ignoreMap":101},[18,228,229,232],{},[14,230,231],{},"joins",": mệnh đề nối được sử dụng để kết hợp các hàng từ hai hoặc nhiều bảng, dựa trên một cột có liên quan. Ví dụ bên dưới là 2 bảng student với project  có mối quan hệ là 1-n:",[18,234,235],{},"student:  id, name, email, phone",[18,237,238],{},"project : id, name, student_id",[18,240,241],{},[14,242,243],{},"leftJoinAndSelect",[92,245,248],{"className":246,"code":247,"language":97},[95],"const student = await getConnection().createQueryBuilder().from(\"student\", \"student\")\n.leftJoinAndSelect(\"project\", \"project\", \"project.student_id = student.id\")\n.where(\"student.name = :name\", { name: \"Student1\" })\n.getOne();\n",[99,249,247],{"__ignoreMap":101},[18,251,140],{},[92,253,256],{"className":254,"code":255,"language":97},[95],"SELECT student.*, project.* FROM student student LEFT JOIN project project \nON project.student_id = student.id WHERE student.name = 'Student1'\n",[99,257,255],{"__ignoreMap":101},[18,259,260],{},[14,261,262],{},"innerJoinAndSelect",[92,264,267],{"className":265,"code":266,"language":97},[95],"const student = await getConnection().createQueryBuilder().from(\"student\", \"student\") \n.innerJoinAndSelect(\"project\", \"project\", \"project.student_id = student.id\") .where(\"student.name = :name\", { name: \"student1\" }) .getOne();\n",[99,268,266],{"__ignoreMap":101},[18,270,271],{},"Truy vấn trên tương đương với:",[92,273,276],{"className":274,"code":275,"language":97},[95],"SELECT student.*, project.* FROM student student INNER JOIN project project \nON project.student_id = student.id WHERE student.name = 'student1';\n",[99,277,275],{"__ignoreMap":101},[18,279,280],{},[14,281,282],{},"Insert",[92,284,287],{"className":285,"code":286,"language":97},[95],"import {getConnection} from \"typeorm\"; \n\nawait getConnection()\n.createQueryBuilder()\n.insert() \n.into('student') \n.values([ { name: \"test\", email: \"test@gmail.com\", phone: \"09011112222\"},\n { name: \"test2\", email: \"test2@gmail.com\", phone: \"09011112222\"}\n]) \n.execute();\n",[99,288,286],{"__ignoreMap":101},[18,290,291],{},[14,292,293],{},"Update",[92,295,298],{"className":296,"code":297,"language":97},[95],"import {getConnection} from \"typeorm\"; \n\nawait getConnection().createQueryBuilder() \n.update('student') \n.set({ name: \"test3\", email: \"test3@gmail.com\"}) \n.where(\"id = :id\", { id: 1 }) \n.execute(); \n",[99,299,297],{"__ignoreMap":101},[18,301,302],{},[14,303,304],{},"Delete",[92,306,309],{"className":307,"code":308,"language":97},[95],"import {getConnection} from \"typeorm\"; \n\n await getConnection() \n.createQueryBuilder() \n.delete()\n.from('student')\n.where(\"id = :id\", { id: 1 }) .execute();\n",[99,310,308],{"__ignoreMap":101},[18,312,313],{},[14,314,315],{},"Subqueries",[18,317,318],{},"Ví dụ 1: Sử dụng subQuery để select field name trong bảng student các record mà có email chứa chuỗi test",[18,320,321],{},"Ví dụ 2: Sử dụng subQuery để select id lớn nhất trong bảng project thỏa field name có chứa chuỗi test và select ra studentId, studentName, projectId",[92,323,326],{"className":324,"code":325,"language":97},[95],"const student = await getConnection().createQueryBuilder().select(\"student.name\", \"name\") \n.from((subQuery) => { return subQuery.select(\"student.name\", \"name\") \n                     .from(\"student\", \"student\").where(\"student.email like :email\", { email: '%test%'}) },\n                   \"student\") .getRawMany();\n\nconst student = await getConnection().createQueryBuilder()\n.select(`student.id as studentId,student.name as studentName,project.id as projectId`)) \n.from(\"student\", \"student\").leftJoin(\"project\", \"project\", \"project.student_id = student.id\")\n.where (\"project.id = (select max(id) from project where name like '%test%' \")).getRawMany();\n",[99,327,325],{"__ignoreMap":101},[25,329,331],{"id":330},"adding-expression-use-getrepository-with-model",[14,332,333],{},"Adding expression use getRepository() with model",[18,335,336],{},"Ví dụ có model User sau:",[92,338,341],{"className":339,"code":340,"language":97},[95],"import {Entity, PrimaryGeneratedColumn, Column} from \"typeorm\";\n\n@Entity('user') \nexport class User { \n@PrimaryGeneratedColumn() \nid: number;\n \n@Column('varchar', {name: 'name', nullable: true, length: 50}) \nname: string | null; \n\n@Column('int', {name: 'age', nullable: true}) \nname: number | null; \n}\n",[99,342,340],{"__ignoreMap":101},[18,344,345,131],{},[14,346,130],{},[92,348,351],{"className":349,"code":350,"language":97},[95],"getRepository(User).createQueryBuilder(\"user\").where(\"user.id= :id\", { id: 1 });\n",[99,352,350],{"__ignoreMap":101},[18,354,140],{},[92,356,358],{"className":357,"code":144,"language":97},[95],[99,359,144],{"__ignoreMap":101},[18,361,362,152],{},[14,363,151],{},[92,365,368],{"className":366,"code":367,"language":97},[95],"getRepository(User).createQueryBuilder(\"user\").orderBy(\"user.name\");\n",[99,369,367],{"__ignoreMap":101},[18,371,140],{},[92,373,375],{"className":374,"code":164,"language":97},[95],[99,376,164],{"__ignoreMap":101},[18,378,379,172],{},[14,380,171],{},[92,382,385],{"className":383,"code":384,"language":97},[95],"getRepository(User).createQueryBuilder(\"user\") .groupBy(\"user.id\")\n",[99,386,384],{"__ignoreMap":101},[18,388,140],{},[92,390,392],{"className":391,"code":184,"language":97},[95],[99,393,184],{"__ignoreMap":101},[18,395,396,192],{},[14,397,191],{},[92,399,402],{"className":400,"code":401,"language":97},[95],"getRepository(User).createQueryBuilder(\"user\").limit(5);\n",[99,403,401],{"__ignoreMap":101},[18,405,140],{},[92,407,409],{"className":408,"code":204,"language":97},[95],[99,410,204],{"__ignoreMap":101},[18,412,413,212],{},[14,414,211],{},[92,416,419],{"className":417,"code":418,"language":97},[95],"getRepository(User).createQueryBuilder(\"user\") .offset(5);\n",[99,420,418],{"__ignoreMap":101},[18,422,140],{},[92,424,426],{"className":425,"code":224,"language":97},[95],[99,427,224],{"__ignoreMap":101},[18,429,430,432],{},[14,431,231],{},": mệnh đề nối được sử dụng để kết hợp các hàng từ hai hoặc nhiều bảng, dựa trên một cột có liên quan. Hãy xem xét hai thực thể:",[92,434,437],{"className":435,"code":436,"language":97},[95],"import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from \"typeorm\";\nimport {Project} from \".\u002FProject\"; \n\n@Entity('student')\nexport class Student { \n@PrimaryGeneratedColumn()\nid: number; \n\n@Column('varchar', {name: 'name', nullable: true, length: 50})\nname: string | null;\n\n@Column('varchar', {name: 'email', nullable: true, length: 30})\nemail: string | null;\n\n@Column('varchar', {name: 'phone', nullable: true, length: 11})\nphone: string | null;\n\n@OneToMany(()=> Project, project => project.student) \nprojects: project[]; \n} \n",[99,438,436],{"__ignoreMap":101},[92,440,443],{"className":441,"code":442,"language":97},[95],"import {Entity, PrimaryGeneratedColumn, Column, ManyToOne}\n\nfrom \"typeorm\"; import {Student} from \".\u002FStudent\";\n\n@Entity('project') \nexport class Project {\n\n@PrimaryGeneratedColumn() \nid: number;\n\n@Column('varchar', {name: 'name', nullable: true, length: 50})\nname: string | null;\n\n@Column('bigint', {name: 'student_id', nullable: true, unsigned: true})\nstudentId: number | null;\n\n@ManyToOne(() => Student, student => student.projects)\n@JoinColumn([{name: 'student_id', referencedColumnName: 'id'}])\nstudent : Student;\n}\n",[99,444,442],{"__ignoreMap":101},[18,446,447],{},[14,448,243],{},[92,450,453],{"className":451,"code":452,"language":97},[95],"const student = await getRepository(Student).createQueryBuilder(\"student\")\n.leftJoinAndSelect(\"student.projects\", \"project\")\n.where(\"student.name = :name\", { name: \"Student1\" })\n.getOne();\n",[99,454,452],{"__ignoreMap":101},[18,456,140],{},[92,458,461],{"className":459,"code":460,"language":97},[95],"SELECT student.*, project.* FROM student student LEFT JOIN projects project \nON project.student = student.id WHERE student.name = 'Student1'\n",[99,462,460],{"__ignoreMap":101},[18,464,465],{},[14,466,262],{},[92,468,471],{"className":469,"code":470,"language":97},[95],"const student = await getRepository(Student).createQueryBuilder(\"student\")\n.innerJoinAndSelect(\"student.projects\", \"project\")\n.where(\"student.name = :name\", { name: \"student1\" })\n.getOne();\n",[99,472,470],{"__ignoreMap":101},[18,474,271],{},[92,476,479],{"className":477,"code":478,"language":97},[95],"SELECT student.*, project.* FROM students student INNER JOIN projects project \nON project.student = student.id WHERE student.name = 'Student1';\n",[99,480,478],{"__ignoreMap":101},[18,482,483],{},[14,484,282],{},[92,486,489],{"className":487,"code":488,"language":97},[95],"import {getConnection} from \"typeorm\"; \n\nawait getRepository(Student)\n.createQueryBuilder() \n.insert() \n.into(Student) \n.values([ { name: \"test\", email: \"test@gmail.com\", phone: \"09011112222\"}, \n{ name: \"test2\", email: \"test2@gmail.com\", phone: \"09011112222\"} ]) \n.execute();\n",[99,490,488],{"__ignoreMap":101},[18,492,493],{},[14,494,293],{},[92,496,499],{"className":497,"code":498,"language":97},[95],"import {getConnection} from \"typeorm\"; \n\nawait getRepository(Student)\n.createQueryBuilder() \n.update(Student) \n.set({ name: \"test3\", email: \"test3@gmail.com\"}) \n.where(\"id = :id\", { id: 1 }) .execute();\n",[99,500,498],{"__ignoreMap":101},[18,502,503],{},[14,504,304],{},[92,506,509],{"className":507,"code":508,"language":97},[95],"import {getConnection} from \"typeorm\"; \nawait getRepository(Student).createQueryBuilder() \n.delete() \n.from(Student) \n.where(\"id = :id\", { id: 1 }) \n.execute();\n",[99,510,508],{"__ignoreMap":101},[10,512,514],{"id":513},"kết-luận","Kết luận",[18,516,517],{},"Nên sử dụng query builder bởi vì nó có thể build các câu sql từ dễ đến phức tạp",[18,519,520],{},"Syntax cũng tương tự gần giống với sql thuần nên rất dễ viết code và đọc hiểu",[18,522,523],{},"Cũng có thể sử dụng query builder một cách bình thường mà không cần dùng đến khai báo model",[18,525,526],{},"Về hiệu năng thì sử dụng query builder thời gian truy xuất sẽ nhanh hơn sử dụng repository api có sẵn của typeorm",[10,528,530],{"id":529},"tài-liệu-tham-khảo","Tài liệu tham khảo",[18,532,533],{},[534,535,536],"a",{"href":536,"rel":537},"https:\u002F\u002Ftypeorm.io\u002F",[538],"nofollow",{"title":101,"searchDepth":540,"depth":540,"links":541},2,[542,548,554,555],{"id":12,"depth":540,"text":16,"children":543},[544,546,547],{"id":27,"depth":545,"text":28},3,{"id":37,"depth":545,"text":38},{"id":53,"depth":545,"text":54},{"id":75,"depth":540,"text":78,"children":549},[550,551,552,553],{"id":84,"depth":545,"text":87},{"id":104,"depth":545,"text":107},{"id":119,"depth":545,"text":122},{"id":330,"depth":545,"text":333},{"id":513,"depth":540,"text":514},{"id":529,"depth":540,"text":530},"tech talk","Briswell Vietnam Co Ltd","2022-06-29","Giới thiệu TypeORM là một ORM có thể chạy trong các nền tảng NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo và Electron và có thể được sử dụng với TypeScript và JavaScript (ES5, ES6, ES7, ES8). Mục tiêu của nó là luôn hỗ trợ các tính năng JavaScript mới nhất và cung cấp các tính năng bổ sung giúp bạn phát triển bất kỳ loại ứng dụng nào sử dụng cơ sở dữ liệu - từ các ứng dụng nhỏ với một vài bảng đến các ứng dụng doanh nghiệp quy mô lớn với nhiều cơ sở dữ liệu.","md",{},true,"\u002Fvi\u002Fnews\u002Ftypeorm",null,{"title":5,"description":559},"vi\u002Fnews\u002Ftypeorm","https:\u002F\u002Fs3-ap-southeast-1.amazonaws.com\u002Fhomepage-media\u002Fwp-content\u002Fuploads\u002F2022\u002F06\u002F08154314\u002Fquerybuilder-typeorm.jpg","LAxulkHwdIfBsVIcWC9XQ66ERJXOOUcQlmhZwvPP9W4",1782205038747]