[{"data":1,"prerenderedAt":3089},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-database-postgresql-tich-hop-csharp":420,"-tu-hoc-database-postgresql-tich-hop-csharp-surround":3084},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":422,"body":423,"description":3077,"extension":3078,"links":3079,"meta":3080,"navigation":3081,"path":220,"seo":3082,"stem":221,"__hash__":3083},"docs\u002F2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp.md","Tích hợp PostgreSQL với C# (Npgsql)",{"type":424,"value":425,"toc":3048},"minimark",[426,431,444,449,501,524,552,556,560,566,628,656,660,812,816,858,872,876,890,900,915,919,923,994,998,1064,1078,1092,1096,1170,1175,1190,1204,1208,1264,1268,1303,1307,1314,1330,1571,1583,1587,1781,1817,1822,1851,1855,1861,1942,2028,2063,2067,2156,2255,2303,2307,2311,2500,2504,2520,2600,2604,2620,2670,2727,2731,2965,2969,3036,3044],[427,428,430],"h2",{"id":429},"_1-tổng-quan","1. Tổng quan",[432,433,434,438,439,443],"p",{},[435,436,437],"strong",{},"Npgsql"," là .NET Data Provider chính thức cho PostgreSQL — tương đương ",[440,441,442],"code",{},"SqlClient"," của SQL Server. Npgsql implement đầy đủ ADO.NET, hỗ trợ async, connection pooling, và PostgreSQL-specific types (JSONB, array, UUID, range...).",[445,446,448],"h3",{"id":447},"cài-đặt","Cài đặt",[450,451,456],"pre",{"className":452,"code":453,"language":454,"meta":455,"style":455},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dotnet add package Npgsql\ndotnet add package Microsoft.Extensions.Configuration\ndotnet add package Microsoft.Extensions.Configuration.Json\n","bash","",[440,457,458,477,489],{"__ignoreMap":455},[459,460,463,467,471,474],"span",{"class":461,"line":462},"line",1,[459,464,466],{"class":465},"sBMFI","dotnet",[459,468,470],{"class":469},"sfazB"," add",[459,472,473],{"class":469}," package",[459,475,476],{"class":469}," Npgsql\n",[459,478,480,482,484,486],{"class":461,"line":479},2,[459,481,466],{"class":465},[459,483,470],{"class":469},[459,485,473],{"class":469},[459,487,488],{"class":469}," Microsoft.Extensions.Configuration\n",[459,490,492,494,496,498],{"class":461,"line":491},3,[459,493,466],{"class":465},[459,495,470],{"class":469},[459,497,473],{"class":469},[459,499,500],{"class":469}," Microsoft.Extensions.Configuration.Json\n",[502,503,504,510],"ul",{},[505,506,507,509],"li",{},[440,508,437],{}," — driver chính để kết nối và thao tác với PostgreSQL.",[505,511,512,515,516,519,520,523],{},[440,513,514],{},"Microsoft.Extensions.Configuration"," + ",[440,517,518],{},"Configuration.Json"," — đọc connection string từ ",[440,521,522],{},"appsettings.json",".",[525,526,529,540],"callout",{"color":527,"icon":528},"primary","i-lucide-star",[432,530,531,532,535,536],{},"⭐ ",[435,533,534],{},"Câu PV:"," ",[537,538,539],"em",{},"\"Trong .NET, dùng thư viện gì để kết nối PostgreSQL?\"",[541,542,543],"blockquote",{},[432,544,545,546,548,549,551],{},"\"",[435,547,437],{}," — .NET Data Provider chính thức cho PostgreSQL. Tương tự ",[440,550,442],{}," cho SQL Server. Hỗ trợ đầy đủ ADO.NET, async\u002Fawait, và tất cả PostgreSQL-specific types như JSONB, array, UUID, INET...\"",[427,553,555],{"id":554},"_2-kết-nối-postgresql-từ-c","2. Kết nối PostgreSQL từ C#",[445,557,559],{"id":558},"connection-string","Connection string",[432,561,562,563,565],{},"File ",[440,564,522],{},":",[450,567,571],{"className":568,"code":569,"language":570,"meta":455,"style":455},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"ConnectionStrings\": {\n    \"DefaultConnection\": \"Server=localhost;Database=elearning;User Id=ed;Password=YourPassword;\"\n  }\n}\n","json",[440,572,573,579,595,616,622],{"__ignoreMap":455},[459,574,575],{"class":461,"line":462},[459,576,578],{"class":577},"sMK4o","{\n",[459,580,581,584,588,590,592],{"class":461,"line":479},[459,582,583],{"class":577},"  \"",[459,585,587],{"class":586},"spNyl","ConnectionStrings",[459,589,545],{"class":577},[459,591,565],{"class":577},[459,593,594],{"class":577}," {\n",[459,596,597,600,603,605,607,610,613],{"class":461,"line":491},[459,598,599],{"class":577},"    \"",[459,601,602],{"class":465},"DefaultConnection",[459,604,545],{"class":577},[459,606,565],{"class":577},[459,608,609],{"class":577}," \"",[459,611,612],{"class":469},"Server=localhost;Database=elearning;User Id=ed;Password=YourPassword;",[459,614,615],{"class":577},"\"\n",[459,617,619],{"class":461,"line":618},4,[459,620,621],{"class":577},"  }\n",[459,623,625],{"class":461,"line":624},5,[459,626,627],{"class":577},"}\n",[525,629,632,637,645],{"color":630,"icon":631},"info","i-lucide-info",[432,633,634],{},[435,635,636],{},"Format connection string PostgreSQL:",[450,638,643],{"className":639,"code":641,"language":642},[640],"language-text","Server=host;Port=5432;Database=dbname;User Id=user;Password=pwd;\n","text",[440,644,641],{"__ignoreMap":455},[432,646,647,648,651,652,655],{},"Không dùng ",[440,649,650],{},"Data Source"," \u002F ",[440,653,654],{},"Initial Catalog"," như SQL Server.",[445,657,659],{"id":658},"configurationhelper-đọc-connection-string","ConfigurationHelper — đọc connection string",[450,661,665],{"className":662,"code":663,"language":664,"meta":455,"style":455},"language-cs shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","using Microsoft.Extensions.Configuration;\n\npublic static class ConfigurationHelper\n{\n    private static readonly IConfiguration _configuration;\n\n    static ConfigurationHelper()\n    {\n        var builder = new ConfigurationBuilder()\n            .SetBasePath(Directory.GetCurrentDirectory())\n            .AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n\n        _configuration = builder.Build();\n    }\n\n    public static string GetConnectionString(string name)\n    {\n        var connectionString = _configuration.GetConnectionString(name);\n        if (string.IsNullOrEmpty(connectionString))\n        {\n            throw new InvalidOperationException(\n                $\"The connection string '{name}' has not been initialized.\");\n        }\n        return connectionString;\n    }\n}\n","cs",[440,666,667,672,678,683,687,692,697,703,709,715,721,727,732,738,744,749,755,760,766,772,778,784,790,796,802,807],{"__ignoreMap":455},[459,668,669],{"class":461,"line":462},[459,670,671],{},"using Microsoft.Extensions.Configuration;\n",[459,673,674],{"class":461,"line":479},[459,675,677],{"emptyLinePlaceholder":676},true,"\n",[459,679,680],{"class":461,"line":491},[459,681,682],{},"public static class ConfigurationHelper\n",[459,684,685],{"class":461,"line":618},[459,686,578],{},[459,688,689],{"class":461,"line":624},[459,690,691],{},"    private static readonly IConfiguration _configuration;\n",[459,693,695],{"class":461,"line":694},6,[459,696,677],{"emptyLinePlaceholder":676},[459,698,700],{"class":461,"line":699},7,[459,701,702],{},"    static ConfigurationHelper()\n",[459,704,706],{"class":461,"line":705},8,[459,707,708],{},"    {\n",[459,710,712],{"class":461,"line":711},9,[459,713,714],{},"        var builder = new ConfigurationBuilder()\n",[459,716,718],{"class":461,"line":717},10,[459,719,720],{},"            .SetBasePath(Directory.GetCurrentDirectory())\n",[459,722,724],{"class":461,"line":723},11,[459,725,726],{},"            .AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n",[459,728,730],{"class":461,"line":729},12,[459,731,677],{"emptyLinePlaceholder":676},[459,733,735],{"class":461,"line":734},13,[459,736,737],{},"        _configuration = builder.Build();\n",[459,739,741],{"class":461,"line":740},14,[459,742,743],{},"    }\n",[459,745,747],{"class":461,"line":746},15,[459,748,677],{"emptyLinePlaceholder":676},[459,750,752],{"class":461,"line":751},16,[459,753,754],{},"    public static string GetConnectionString(string name)\n",[459,756,758],{"class":461,"line":757},17,[459,759,708],{},[459,761,763],{"class":461,"line":762},18,[459,764,765],{},"        var connectionString = _configuration.GetConnectionString(name);\n",[459,767,769],{"class":461,"line":768},19,[459,770,771],{},"        if (string.IsNullOrEmpty(connectionString))\n",[459,773,775],{"class":461,"line":774},20,[459,776,777],{},"        {\n",[459,779,781],{"class":461,"line":780},21,[459,782,783],{},"            throw new InvalidOperationException(\n",[459,785,787],{"class":461,"line":786},22,[459,788,789],{},"                $\"The connection string '{name}' has not been initialized.\");\n",[459,791,793],{"class":461,"line":792},23,[459,794,795],{},"        }\n",[459,797,799],{"class":461,"line":798},24,[459,800,801],{},"        return connectionString;\n",[459,803,805],{"class":461,"line":804},25,[459,806,743],{},[459,808,810],{"class":461,"line":809},26,[459,811,627],{},[445,813,815],{"id":814},"kết-nối-cơ-bản-npgsqlconnection","Kết nối cơ bản — NpgsqlConnection",[450,817,819],{"className":662,"code":818,"language":664,"meta":455,"style":455},"using Npgsql;\n\nstring connectionString = ConfigurationHelper.GetConnectionString(\"DefaultConnection\");\n\nawait using var conn = new NpgsqlConnection(connectionString);\nawait conn.OpenAsync();\n\nConsole.WriteLine($\"The PostgreSQL version: {conn.PostgreSqlVersion}\");\n",[440,820,821,826,830,835,839,844,849,853],{"__ignoreMap":455},[459,822,823],{"class":461,"line":462},[459,824,825],{},"using Npgsql;\n",[459,827,828],{"class":461,"line":479},[459,829,677],{"emptyLinePlaceholder":676},[459,831,832],{"class":461,"line":491},[459,833,834],{},"string connectionString = ConfigurationHelper.GetConnectionString(\"DefaultConnection\");\n",[459,836,837],{"class":461,"line":618},[459,838,677],{"emptyLinePlaceholder":676},[459,840,841],{"class":461,"line":624},[459,842,843],{},"await using var conn = new NpgsqlConnection(connectionString);\n",[459,845,846],{"class":461,"line":694},[459,847,848],{},"await conn.OpenAsync();\n",[459,850,851],{"class":461,"line":699},[459,852,677],{"emptyLinePlaceholder":676},[459,854,855],{"class":461,"line":705},[459,856,857],{},"Console.WriteLine($\"The PostgreSQL version: {conn.PostgreSqlVersion}\");\n",[525,859,531,861,535,864,867,868,871],{"color":860,"icon":528},"warning",[435,862,863],{},"Pattern quan trọng:",[440,865,866],{},"await using"," đảm bảo connection được dispose (trả về pool) ngay khi ra khỏi scope. Không đóng connection → ",[435,869,870],{},"connection leak"," → crash app.",[445,873,875],{"id":874},"npgsqldatasource-npgsql-70-khuyên-dùng","NpgsqlDataSource (Npgsql 7.0+) — khuyên dùng",[450,877,879],{"className":662,"code":878,"language":664,"meta":455,"style":455},"string connectionString = ConfigurationHelper.GetConnectionString(\"DefaultConnection\");\nawait using var dataSource = NpgsqlDataSource.Create(connectionString);\n",[440,880,881,885],{"__ignoreMap":455},[459,882,883],{"class":461,"line":462},[459,884,834],{},[459,886,887],{"class":461,"line":479},[459,888,889],{},"await using var dataSource = NpgsqlDataSource.Create(connectionString);\n",[432,891,892,895,896,899],{},[440,893,894],{},"NpgsqlDataSource"," là factory quản lý connection tự động, thread-safe. Nên tạo ",[435,897,898],{},"một instance duy nhất"," cho toàn bộ application.",[450,901,903],{"className":662,"code":902,"language":664,"meta":455,"style":455},"\u002F\u002F Lấy connection từ data source khi cần thao tác thủ công\nawait using var conn = await dataSource.OpenConnectionAsync();\n",[440,904,905,910],{"__ignoreMap":455},[459,906,907],{"class":461,"line":462},[459,908,909],{},"\u002F\u002F Lấy connection từ data source khi cần thao tác thủ công\n",[459,911,912],{"class":461,"line":479},[459,913,914],{},"await using var conn = await dataSource.OpenConnectionAsync();\n",[427,916,918],{"id":917},"_3-crud-thao-tác-cơ-bản","3. CRUD — thao tác cơ bản",[445,920,922],{"id":921},"tạo-bảng-create-table","Tạo bảng (CREATE TABLE)",[450,924,926],{"className":662,"code":925,"language":664,"meta":455,"style":455},"await using var dataSource = NpgsqlDataSource.Create(connectionString);\n\nvar sql = @\"CREATE TABLE IF NOT EXISTS students (\n    id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    first_name VARCHAR(100) NOT NULL,\n    last_name VARCHAR(100) NOT NULL,\n    email VARCHAR(255) UNIQUE NOT NULL,\n    registration_date DATE NOT NULL\n)\";\n\nawait using var cmd = dataSource.CreateCommand(sql);\nawait cmd.ExecuteNonQueryAsync();\n\nConsole.WriteLine(\"Table 'students' created successfully.\");\n",[440,927,928,932,936,941,946,951,956,961,966,971,975,980,985,989],{"__ignoreMap":455},[459,929,930],{"class":461,"line":462},[459,931,889],{},[459,933,934],{"class":461,"line":479},[459,935,677],{"emptyLinePlaceholder":676},[459,937,938],{"class":461,"line":491},[459,939,940],{},"var sql = @\"CREATE TABLE IF NOT EXISTS students (\n",[459,942,943],{"class":461,"line":618},[459,944,945],{},"    id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n",[459,947,948],{"class":461,"line":624},[459,949,950],{},"    first_name VARCHAR(100) NOT NULL,\n",[459,952,953],{"class":461,"line":694},[459,954,955],{},"    last_name VARCHAR(100) NOT NULL,\n",[459,957,958],{"class":461,"line":699},[459,959,960],{},"    email VARCHAR(255) UNIQUE NOT NULL,\n",[459,962,963],{"class":461,"line":705},[459,964,965],{},"    registration_date DATE NOT NULL\n",[459,967,968],{"class":461,"line":711},[459,969,970],{},")\";\n",[459,972,973],{"class":461,"line":717},[459,974,677],{"emptyLinePlaceholder":676},[459,976,977],{"class":461,"line":723},[459,978,979],{},"await using var cmd = dataSource.CreateCommand(sql);\n",[459,981,982],{"class":461,"line":729},[459,983,984],{},"await cmd.ExecuteNonQueryAsync();\n",[459,986,987],{"class":461,"line":734},[459,988,677],{"emptyLinePlaceholder":676},[459,990,991],{"class":461,"line":740},[459,992,993],{},"Console.WriteLine(\"Table 'students' created successfully.\");\n",[445,995,997],{"id":996},"thêm-dữ-liệu-insert","Thêm dữ liệu (INSERT)",[450,999,1001],{"className":662,"code":1000,"language":664,"meta":455,"style":455},"var sql = @\"INSERT INTO students (first_name, last_name, email, registration_date)\n            VALUES (@first_name, @last_name, @email, @registration_date)\n            RETURNING id\";\n\nawait using var cmd = dataSource.CreateCommand(sql);\n\ncmd.Parameters.AddWithValue(\"@first_name\", \"Nguyen\");\ncmd.Parameters.AddWithValue(\"@last_name\", \"Van A\");\ncmd.Parameters.AddWithValue(\"@email\", \"nguyenvana@example.com\");\ncmd.Parameters.AddWithValue(\"@registration_date\", new DateOnly(2026, 7, 8));\n\nvar newId = await cmd.ExecuteScalarAsync();\nConsole.WriteLine($\"Inserted student with id: {newId}\");\n",[440,1002,1003,1008,1013,1018,1022,1026,1030,1035,1040,1045,1050,1054,1059],{"__ignoreMap":455},[459,1004,1005],{"class":461,"line":462},[459,1006,1007],{},"var sql = @\"INSERT INTO students (first_name, last_name, email, registration_date)\n",[459,1009,1010],{"class":461,"line":479},[459,1011,1012],{},"            VALUES (@first_name, @last_name, @email, @registration_date)\n",[459,1014,1015],{"class":461,"line":491},[459,1016,1017],{},"            RETURNING id\";\n",[459,1019,1020],{"class":461,"line":618},[459,1021,677],{"emptyLinePlaceholder":676},[459,1023,1024],{"class":461,"line":624},[459,1025,979],{},[459,1027,1028],{"class":461,"line":694},[459,1029,677],{"emptyLinePlaceholder":676},[459,1031,1032],{"class":461,"line":699},[459,1033,1034],{},"cmd.Parameters.AddWithValue(\"@first_name\", \"Nguyen\");\n",[459,1036,1037],{"class":461,"line":705},[459,1038,1039],{},"cmd.Parameters.AddWithValue(\"@last_name\", \"Van A\");\n",[459,1041,1042],{"class":461,"line":711},[459,1043,1044],{},"cmd.Parameters.AddWithValue(\"@email\", \"nguyenvana@example.com\");\n",[459,1046,1047],{"class":461,"line":717},[459,1048,1049],{},"cmd.Parameters.AddWithValue(\"@registration_date\", new DateOnly(2026, 7, 8));\n",[459,1051,1052],{"class":461,"line":723},[459,1053,677],{"emptyLinePlaceholder":676},[459,1055,1056],{"class":461,"line":729},[459,1057,1058],{},"var newId = await cmd.ExecuteScalarAsync();\n",[459,1060,1061],{"class":461,"line":734},[459,1062,1063],{},"Console.WriteLine($\"Inserted student with id: {newId}\");\n",[525,1065,1066,1067,1070,1071,1074,1075,655],{"color":527,"icon":268},"Dùng ",[440,1068,1069],{},"RETURNING id"," để lấy ID vừa insert — không cần ",[440,1072,1073],{},"SELECT LASTVAL()"," hay ",[440,1076,1077],{},"SCOPE_IDENTITY()",[525,1079,531,1080,1083,1084,1087,1088,1091],{"color":860,"icon":528},[435,1081,1082],{},"Tránh SQL injection:"," luôn dùng ",[435,1085,1086],{},"parameterized query"," (",[440,1089,1090],{},"@param","), không bao giờ nối chuỗi trực tiếp. Npgsql tự escape và chọn đúng kiểu dữ liệu PostgreSQL.",[445,1093,1095],{"id":1094},"truy-vấn-dữ-liệu-select","Truy vấn dữ liệu (SELECT)",[450,1097,1099],{"className":662,"code":1098,"language":664,"meta":455,"style":455},"var sql = \"SELECT id, first_name, last_name, email, registration_date FROM students\";\n\nawait using var cmd = dataSource.CreateCommand(sql);\nawait using var reader = await cmd.ExecuteReaderAsync();\n\nwhile (await reader.ReadAsync())\n{\n    var id = reader.GetInt32(0);\n    var firstName = reader.GetString(1);\n    var lastName = reader.GetString(2);\n    var email = reader.GetString(3);\n    var regDate = reader.GetFieldValue\u003CDateOnly>(4);\n\n    Console.WriteLine($\"{id}: {firstName} {lastName} ({email}) - {regDate}\");\n}\n",[440,1100,1101,1106,1110,1114,1119,1123,1128,1132,1137,1142,1147,1152,1157,1161,1166],{"__ignoreMap":455},[459,1102,1103],{"class":461,"line":462},[459,1104,1105],{},"var sql = \"SELECT id, first_name, last_name, email, registration_date FROM students\";\n",[459,1107,1108],{"class":461,"line":479},[459,1109,677],{"emptyLinePlaceholder":676},[459,1111,1112],{"class":461,"line":491},[459,1113,979],{},[459,1115,1116],{"class":461,"line":618},[459,1117,1118],{},"await using var reader = await cmd.ExecuteReaderAsync();\n",[459,1120,1121],{"class":461,"line":624},[459,1122,677],{"emptyLinePlaceholder":676},[459,1124,1125],{"class":461,"line":694},[459,1126,1127],{},"while (await reader.ReadAsync())\n",[459,1129,1130],{"class":461,"line":699},[459,1131,578],{},[459,1133,1134],{"class":461,"line":705},[459,1135,1136],{},"    var id = reader.GetInt32(0);\n",[459,1138,1139],{"class":461,"line":711},[459,1140,1141],{},"    var firstName = reader.GetString(1);\n",[459,1143,1144],{"class":461,"line":717},[459,1145,1146],{},"    var lastName = reader.GetString(2);\n",[459,1148,1149],{"class":461,"line":723},[459,1150,1151],{},"    var email = reader.GetString(3);\n",[459,1153,1154],{"class":461,"line":729},[459,1155,1156],{},"    var regDate = reader.GetFieldValue\u003CDateOnly>(4);\n",[459,1158,1159],{"class":461,"line":734},[459,1160,677],{"emptyLinePlaceholder":676},[459,1162,1163],{"class":461,"line":740},[459,1164,1165],{},"    Console.WriteLine($\"{id}: {firstName} {lastName} ({email}) - {regDate}\");\n",[459,1167,1168],{"class":461,"line":746},[459,1169,627],{},[432,1171,1172],{},[435,1173,1174],{},"Đọc theo tên cột (an toàn hơn):",[450,1176,1178],{"className":662,"code":1177,"language":664,"meta":455,"style":455},"var id = reader.GetInt32(\"id\");\nvar firstName = reader.GetString(\"first_name\");\n",[440,1179,1180,1185],{"__ignoreMap":455},[459,1181,1182],{"class":461,"line":462},[459,1183,1184],{},"var id = reader.GetInt32(\"id\");\n",[459,1186,1187],{"class":461,"line":479},[459,1188,1189],{},"var firstName = reader.GetString(\"first_name\");\n",[525,1191,1192,1195,1196,1199,1200,1203],{"color":630,"icon":631},[440,1193,1194],{},"NpgsqlDataReader"," hỗ trợ cả ",[440,1197,1198],{},"GetInt32(ordinal)"," theo index lẫn ",[440,1201,1202],{},"GetString(\"column_name\")"," theo tên. Đọc theo tên an toàn hơn khi thay đổi thứ tự cột SELECT.",[445,1205,1207],{"id":1206},"cập-nhật-dữ-liệu-update","Cập nhật dữ liệu (UPDATE)",[450,1209,1211],{"className":662,"code":1210,"language":664,"meta":455,"style":455},"var sql = @\"UPDATE students\n            SET email = @email\n            WHERE id = @id\";\n\nawait using var cmd = dataSource.CreateCommand(sql);\n\ncmd.Parameters.AddWithValue(\"@email\", \"newemail@example.com\");\ncmd.Parameters.AddWithValue(\"@id\", 1);\n\nvar rowsAffected = await cmd.ExecuteNonQueryAsync();\nConsole.WriteLine($\"Updated {rowsAffected} row(s).\");\n",[440,1212,1213,1218,1223,1228,1232,1236,1240,1245,1250,1254,1259],{"__ignoreMap":455},[459,1214,1215],{"class":461,"line":462},[459,1216,1217],{},"var sql = @\"UPDATE students\n",[459,1219,1220],{"class":461,"line":479},[459,1221,1222],{},"            SET email = @email\n",[459,1224,1225],{"class":461,"line":491},[459,1226,1227],{},"            WHERE id = @id\";\n",[459,1229,1230],{"class":461,"line":618},[459,1231,677],{"emptyLinePlaceholder":676},[459,1233,1234],{"class":461,"line":624},[459,1235,979],{},[459,1237,1238],{"class":461,"line":694},[459,1239,677],{"emptyLinePlaceholder":676},[459,1241,1242],{"class":461,"line":699},[459,1243,1244],{},"cmd.Parameters.AddWithValue(\"@email\", \"newemail@example.com\");\n",[459,1246,1247],{"class":461,"line":705},[459,1248,1249],{},"cmd.Parameters.AddWithValue(\"@id\", 1);\n",[459,1251,1252],{"class":461,"line":711},[459,1253,677],{"emptyLinePlaceholder":676},[459,1255,1256],{"class":461,"line":717},[459,1257,1258],{},"var rowsAffected = await cmd.ExecuteNonQueryAsync();\n",[459,1260,1261],{"class":461,"line":723},[459,1262,1263],{},"Console.WriteLine($\"Updated {rowsAffected} row(s).\");\n",[445,1265,1267],{"id":1266},"xoá-dữ-liệu-delete","Xoá dữ liệu (DELETE)",[450,1269,1271],{"className":662,"code":1270,"language":664,"meta":455,"style":455},"var sql = \"DELETE FROM students WHERE id = @id\";\n\nawait using var cmd = dataSource.CreateCommand(sql);\ncmd.Parameters.AddWithValue(\"@id\", 1);\n\nvar rowsAffected = await cmd.ExecuteNonQueryAsync();\nConsole.WriteLine($\"Deleted {rowsAffected} row(s).\");\n",[440,1272,1273,1278,1282,1286,1290,1294,1298],{"__ignoreMap":455},[459,1274,1275],{"class":461,"line":462},[459,1276,1277],{},"var sql = \"DELETE FROM students WHERE id = @id\";\n",[459,1279,1280],{"class":461,"line":479},[459,1281,677],{"emptyLinePlaceholder":676},[459,1283,1284],{"class":461,"line":491},[459,1285,979],{},[459,1287,1288],{"class":461,"line":618},[459,1289,1249],{},[459,1291,1292],{"class":461,"line":624},[459,1293,677],{"emptyLinePlaceholder":676},[459,1295,1296],{"class":461,"line":694},[459,1297,1258],{},[459,1299,1300],{"class":461,"line":699},[459,1301,1302],{},"Console.WriteLine($\"Deleted {rowsAffected} row(s).\");\n",[427,1304,1306],{"id":1305},"_4-import-dữ-liệu-từ-csv","4. Import dữ liệu từ CSV",[432,1308,1309,1310,1313],{},"Dùng package ",[440,1311,1312],{},"CsvHelper"," để parse CSV, sau đó INSERT từng dòng:",[450,1315,1317],{"className":452,"code":1316,"language":454,"meta":455,"style":455},"dotnet add package CsvHelper\n",[440,1318,1319],{"__ignoreMap":455},[459,1320,1321,1323,1325,1327],{"class":461,"line":462},[459,1322,466],{"class":465},[459,1324,470],{"class":469},[459,1326,473],{"class":469},[459,1328,1329],{"class":469}," CsvHelper\n",[450,1331,1333],{"className":662,"code":1332,"language":664,"meta":455,"style":455},"using CsvHelper;\nusing System.Globalization;\nusing Npgsql;\n\npublic record Student(string FirstName, string LastName, string Email, DateOnly RegistrationDate);\n\npublic static IEnumerable\u003CStudent> ReadStudentsFromCSV(string filePath)\n{\n    using var reader = new StreamReader(filePath);\n    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);\n\n    csv.Read();\n    csv.ReadHeader();\n\n    while (csv.Read())\n    {\n        var firstName = csv.GetField\u003Cstring>(\"Firstname\");\n        var lastName = csv.GetField\u003Cstring>(\"Lastname\");\n        var email = csv.GetField\u003Cstring>(\"Email\");\n        var registrationDate = csv.GetField\u003CDateOnly>(\"RegistrationDate\");\n\n        yield return new Student(firstName, lastName, email, registrationDate);\n    }\n}\n\npublic static async Task Main()\n{\n    var csvFilePath = @\"C:\\data\\students.csv\";\n    var sql = @\"INSERT INTO students(first_name, last_name, email, registration_date)\n                VALUES(@first_name, @last_name, @email, @registration_date)\";\n\n    string connectionString = ConfigurationHelper.GetConnectionString(\"DefaultConnection\");\n\n    await using var dataSource = NpgsqlDataSource.Create(connectionString);\n\n    foreach (var student in ReadStudentsFromCSV(csvFilePath))\n    {\n        await using var cmd = dataSource.CreateCommand(sql);\n\n        cmd.Parameters.AddWithValue(\"@first_name\", student.FirstName);\n        cmd.Parameters.AddWithValue(\"@last_name\", student.LastName);\n        cmd.Parameters.AddWithValue(\"@email\", student.Email);\n        cmd.Parameters.AddWithValue(\"@registration_date\", student.RegistrationDate);\n\n        await cmd.ExecuteNonQueryAsync();\n    }\n}\n",[440,1334,1335,1340,1345,1349,1353,1358,1362,1367,1371,1376,1381,1385,1390,1395,1399,1404,1408,1413,1418,1423,1428,1432,1437,1441,1445,1449,1454,1459,1465,1471,1477,1482,1488,1493,1499,1504,1510,1515,1521,1526,1532,1538,1544,1550,1555,1561,1566],{"__ignoreMap":455},[459,1336,1337],{"class":461,"line":462},[459,1338,1339],{},"using CsvHelper;\n",[459,1341,1342],{"class":461,"line":479},[459,1343,1344],{},"using System.Globalization;\n",[459,1346,1347],{"class":461,"line":491},[459,1348,825],{},[459,1350,1351],{"class":461,"line":618},[459,1352,677],{"emptyLinePlaceholder":676},[459,1354,1355],{"class":461,"line":624},[459,1356,1357],{},"public record Student(string FirstName, string LastName, string Email, DateOnly RegistrationDate);\n",[459,1359,1360],{"class":461,"line":694},[459,1361,677],{"emptyLinePlaceholder":676},[459,1363,1364],{"class":461,"line":699},[459,1365,1366],{},"public static IEnumerable\u003CStudent> ReadStudentsFromCSV(string filePath)\n",[459,1368,1369],{"class":461,"line":705},[459,1370,578],{},[459,1372,1373],{"class":461,"line":711},[459,1374,1375],{},"    using var reader = new StreamReader(filePath);\n",[459,1377,1378],{"class":461,"line":717},[459,1379,1380],{},"    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);\n",[459,1382,1383],{"class":461,"line":723},[459,1384,677],{"emptyLinePlaceholder":676},[459,1386,1387],{"class":461,"line":729},[459,1388,1389],{},"    csv.Read();\n",[459,1391,1392],{"class":461,"line":734},[459,1393,1394],{},"    csv.ReadHeader();\n",[459,1396,1397],{"class":461,"line":740},[459,1398,677],{"emptyLinePlaceholder":676},[459,1400,1401],{"class":461,"line":746},[459,1402,1403],{},"    while (csv.Read())\n",[459,1405,1406],{"class":461,"line":751},[459,1407,708],{},[459,1409,1410],{"class":461,"line":757},[459,1411,1412],{},"        var firstName = csv.GetField\u003Cstring>(\"Firstname\");\n",[459,1414,1415],{"class":461,"line":762},[459,1416,1417],{},"        var lastName = csv.GetField\u003Cstring>(\"Lastname\");\n",[459,1419,1420],{"class":461,"line":768},[459,1421,1422],{},"        var email = csv.GetField\u003Cstring>(\"Email\");\n",[459,1424,1425],{"class":461,"line":774},[459,1426,1427],{},"        var registrationDate = csv.GetField\u003CDateOnly>(\"RegistrationDate\");\n",[459,1429,1430],{"class":461,"line":780},[459,1431,677],{"emptyLinePlaceholder":676},[459,1433,1434],{"class":461,"line":786},[459,1435,1436],{},"        yield return new Student(firstName, lastName, email, registrationDate);\n",[459,1438,1439],{"class":461,"line":792},[459,1440,743],{},[459,1442,1443],{"class":461,"line":798},[459,1444,627],{},[459,1446,1447],{"class":461,"line":804},[459,1448,677],{"emptyLinePlaceholder":676},[459,1450,1451],{"class":461,"line":809},[459,1452,1453],{},"public static async Task Main()\n",[459,1455,1457],{"class":461,"line":1456},27,[459,1458,578],{},[459,1460,1462],{"class":461,"line":1461},28,[459,1463,1464],{},"    var csvFilePath = @\"C:\\data\\students.csv\";\n",[459,1466,1468],{"class":461,"line":1467},29,[459,1469,1470],{},"    var sql = @\"INSERT INTO students(first_name, last_name, email, registration_date)\n",[459,1472,1474],{"class":461,"line":1473},30,[459,1475,1476],{},"                VALUES(@first_name, @last_name, @email, @registration_date)\";\n",[459,1478,1480],{"class":461,"line":1479},31,[459,1481,677],{"emptyLinePlaceholder":676},[459,1483,1485],{"class":461,"line":1484},32,[459,1486,1487],{},"    string connectionString = ConfigurationHelper.GetConnectionString(\"DefaultConnection\");\n",[459,1489,1491],{"class":461,"line":1490},33,[459,1492,677],{"emptyLinePlaceholder":676},[459,1494,1496],{"class":461,"line":1495},34,[459,1497,1498],{},"    await using var dataSource = NpgsqlDataSource.Create(connectionString);\n",[459,1500,1502],{"class":461,"line":1501},35,[459,1503,677],{"emptyLinePlaceholder":676},[459,1505,1507],{"class":461,"line":1506},36,[459,1508,1509],{},"    foreach (var student in ReadStudentsFromCSV(csvFilePath))\n",[459,1511,1513],{"class":461,"line":1512},37,[459,1514,708],{},[459,1516,1518],{"class":461,"line":1517},38,[459,1519,1520],{},"        await using var cmd = dataSource.CreateCommand(sql);\n",[459,1522,1524],{"class":461,"line":1523},39,[459,1525,677],{"emptyLinePlaceholder":676},[459,1527,1529],{"class":461,"line":1528},40,[459,1530,1531],{},"        cmd.Parameters.AddWithValue(\"@first_name\", student.FirstName);\n",[459,1533,1535],{"class":461,"line":1534},41,[459,1536,1537],{},"        cmd.Parameters.AddWithValue(\"@last_name\", student.LastName);\n",[459,1539,1541],{"class":461,"line":1540},42,[459,1542,1543],{},"        cmd.Parameters.AddWithValue(\"@email\", student.Email);\n",[459,1545,1547],{"class":461,"line":1546},43,[459,1548,1549],{},"        cmd.Parameters.AddWithValue(\"@registration_date\", student.RegistrationDate);\n",[459,1551,1553],{"class":461,"line":1552},44,[459,1554,677],{"emptyLinePlaceholder":676},[459,1556,1558],{"class":461,"line":1557},45,[459,1559,1560],{},"        await cmd.ExecuteNonQueryAsync();\n",[459,1562,1564],{"class":461,"line":1563},46,[459,1565,743],{},[459,1567,1569],{"class":461,"line":1568},47,[459,1570,627],{},[525,1572,531,1573,535,1575,1578,1579,1582],{"color":860,"icon":528},[435,1574,863],{},[440,1576,1577],{},"yield return"," trong ",[440,1580,1581],{},"ReadStudentsFromCSV"," giúp stream từng dòng CSV mà không load toàn bộ file vào memory. Với file CSV lớn (hàng trăm MB), đây là pattern bắt buộc.",[427,1584,1586],{"id":1585},"_5-transaction-trong-c","5. Transaction trong C#",[450,1588,1590],{"className":662,"code":1589,"language":664,"meta":455,"style":455},"await using var conn = await dataSource.OpenConnectionAsync();\n\n\u002F\u002F Bắt đầu transaction\nawait using var tx = await conn.BeginTransactionAsync();\n\ntry\n{\n    \u002F\u002F Thao tác 1: Enroll student vào course\n    var sql1 = @\"INSERT INTO enrollments (student_id, course_id, enrolled_date)\n                 VALUES (@student_id, @course_id, @enrolled_date)\";\n\n    await using var cmd1 = new NpgsqlCommand(sql1, conn, tx);\n    cmd1.Parameters.AddWithValue(\"@student_id\", 2);\n    cmd1.Parameters.AddWithValue(\"@course_id\", 1);\n    cmd1.Parameters.AddWithValue(\"@enrolled_date\", new DateOnly(2026, 7, 8));\n    await cmd1.ExecuteNonQueryAsync();\n\n    \u002F\u002F Thao tác 2: Tạo invoice\n    var sql2 = @\"INSERT INTO invoices (student_id, course_id, amount, tax, invoice_date)\n                 VALUES (@student_id, @course_id, @amount, @tax, @invoice_date)\";\n\n    await using var cmd2 = new NpgsqlCommand(sql2, conn, tx);\n    cmd2.Parameters.AddWithValue(\"@student_id\", 2);\n    cmd2.Parameters.AddWithValue(\"@course_id\", 1);\n    cmd2.Parameters.AddWithValue(\"@amount\", 99.5);\n    cmd2.Parameters.AddWithValue(\"@tax\", 0.05);\n    cmd2.Parameters.AddWithValue(\"@invoice_date\", new DateOnly(2026, 7, 8));\n    await cmd2.ExecuteNonQueryAsync();\n\n    \u002F\u002F Commit — lưu tất cả thay đổi\n    await tx.CommitAsync();\n    Console.WriteLine(\"Transaction committed.\");\n}\ncatch (NpgsqlException ex)\n{\n    Console.WriteLine($\"Error: {ex.Message}\");\n    \u002F\u002F Rollback — huỷ tất cả thay đổi\n    await tx.RollbackAsync();\n    Console.WriteLine(\"Transaction rolled back.\");\n}\n",[440,1591,1592,1596,1600,1605,1610,1614,1619,1623,1628,1633,1638,1642,1647,1652,1657,1662,1667,1671,1676,1681,1686,1690,1695,1700,1705,1710,1715,1720,1725,1729,1734,1739,1744,1748,1753,1757,1762,1767,1772,1777],{"__ignoreMap":455},[459,1593,1594],{"class":461,"line":462},[459,1595,914],{},[459,1597,1598],{"class":461,"line":479},[459,1599,677],{"emptyLinePlaceholder":676},[459,1601,1602],{"class":461,"line":491},[459,1603,1604],{},"\u002F\u002F Bắt đầu transaction\n",[459,1606,1607],{"class":461,"line":618},[459,1608,1609],{},"await using var tx = await conn.BeginTransactionAsync();\n",[459,1611,1612],{"class":461,"line":624},[459,1613,677],{"emptyLinePlaceholder":676},[459,1615,1616],{"class":461,"line":694},[459,1617,1618],{},"try\n",[459,1620,1621],{"class":461,"line":699},[459,1622,578],{},[459,1624,1625],{"class":461,"line":705},[459,1626,1627],{},"    \u002F\u002F Thao tác 1: Enroll student vào course\n",[459,1629,1630],{"class":461,"line":711},[459,1631,1632],{},"    var sql1 = @\"INSERT INTO enrollments (student_id, course_id, enrolled_date)\n",[459,1634,1635],{"class":461,"line":717},[459,1636,1637],{},"                 VALUES (@student_id, @course_id, @enrolled_date)\";\n",[459,1639,1640],{"class":461,"line":723},[459,1641,677],{"emptyLinePlaceholder":676},[459,1643,1644],{"class":461,"line":729},[459,1645,1646],{},"    await using var cmd1 = new NpgsqlCommand(sql1, conn, tx);\n",[459,1648,1649],{"class":461,"line":734},[459,1650,1651],{},"    cmd1.Parameters.AddWithValue(\"@student_id\", 2);\n",[459,1653,1654],{"class":461,"line":740},[459,1655,1656],{},"    cmd1.Parameters.AddWithValue(\"@course_id\", 1);\n",[459,1658,1659],{"class":461,"line":746},[459,1660,1661],{},"    cmd1.Parameters.AddWithValue(\"@enrolled_date\", new DateOnly(2026, 7, 8));\n",[459,1663,1664],{"class":461,"line":751},[459,1665,1666],{},"    await cmd1.ExecuteNonQueryAsync();\n",[459,1668,1669],{"class":461,"line":757},[459,1670,677],{"emptyLinePlaceholder":676},[459,1672,1673],{"class":461,"line":762},[459,1674,1675],{},"    \u002F\u002F Thao tác 2: Tạo invoice\n",[459,1677,1678],{"class":461,"line":768},[459,1679,1680],{},"    var sql2 = @\"INSERT INTO invoices (student_id, course_id, amount, tax, invoice_date)\n",[459,1682,1683],{"class":461,"line":774},[459,1684,1685],{},"                 VALUES (@student_id, @course_id, @amount, @tax, @invoice_date)\";\n",[459,1687,1688],{"class":461,"line":780},[459,1689,677],{"emptyLinePlaceholder":676},[459,1691,1692],{"class":461,"line":786},[459,1693,1694],{},"    await using var cmd2 = new NpgsqlCommand(sql2, conn, tx);\n",[459,1696,1697],{"class":461,"line":792},[459,1698,1699],{},"    cmd2.Parameters.AddWithValue(\"@student_id\", 2);\n",[459,1701,1702],{"class":461,"line":798},[459,1703,1704],{},"    cmd2.Parameters.AddWithValue(\"@course_id\", 1);\n",[459,1706,1707],{"class":461,"line":804},[459,1708,1709],{},"    cmd2.Parameters.AddWithValue(\"@amount\", 99.5);\n",[459,1711,1712],{"class":461,"line":809},[459,1713,1714],{},"    cmd2.Parameters.AddWithValue(\"@tax\", 0.05);\n",[459,1716,1717],{"class":461,"line":1456},[459,1718,1719],{},"    cmd2.Parameters.AddWithValue(\"@invoice_date\", new DateOnly(2026, 7, 8));\n",[459,1721,1722],{"class":461,"line":1461},[459,1723,1724],{},"    await cmd2.ExecuteNonQueryAsync();\n",[459,1726,1727],{"class":461,"line":1467},[459,1728,677],{"emptyLinePlaceholder":676},[459,1730,1731],{"class":461,"line":1473},[459,1732,1733],{},"    \u002F\u002F Commit — lưu tất cả thay đổi\n",[459,1735,1736],{"class":461,"line":1479},[459,1737,1738],{},"    await tx.CommitAsync();\n",[459,1740,1741],{"class":461,"line":1484},[459,1742,1743],{},"    Console.WriteLine(\"Transaction committed.\");\n",[459,1745,1746],{"class":461,"line":1490},[459,1747,627],{},[459,1749,1750],{"class":461,"line":1495},[459,1751,1752],{},"catch (NpgsqlException ex)\n",[459,1754,1755],{"class":461,"line":1501},[459,1756,578],{},[459,1758,1759],{"class":461,"line":1506},[459,1760,1761],{},"    Console.WriteLine($\"Error: {ex.Message}\");\n",[459,1763,1764],{"class":461,"line":1512},[459,1765,1766],{},"    \u002F\u002F Rollback — huỷ tất cả thay đổi\n",[459,1768,1769],{"class":461,"line":1517},[459,1770,1771],{},"    await tx.RollbackAsync();\n",[459,1773,1774],{"class":461,"line":1523},[459,1775,1776],{},"    Console.WriteLine(\"Transaction rolled back.\");\n",[459,1778,1779],{"class":461,"line":1528},[459,1780,627],{},[525,1782,1783,1801,1810],{"color":527,"icon":528},[432,1784,531,1785,1788,1789,1792,1793,1796,1797,1800],{},[435,1786,1787],{},"Lưu ý quan trọng:"," Khi dùng transaction, ",[440,1790,1791],{},"NpgsqlCommand"," phải được truyền cả ",[435,1794,1795],{},"connection"," và ",[435,1798,1799],{},"transaction"," object:",[450,1802,1804],{"className":662,"code":1803,"language":664,"meta":455,"style":455},"new NpgsqlCommand(sql, conn, tx)\n",[440,1805,1806],{"__ignoreMap":455},[459,1807,1808],{"class":461,"line":462},[459,1809,1803],{},[432,1811,1812,1813,1816],{},"Thiếu ",[440,1814,1815],{},"tx"," → command chạy ngoài transaction → không rollback được.",[432,1818,1819],{},[435,1820,1821],{},"Các bước chuẩn:",[1823,1824,1825,1831,1838,1844],"ol",{},[505,1826,1827,1830],{},[440,1828,1829],{},"BeginTransactionAsync()"," — bắt đầu transaction.",[505,1832,1833,1834,1837],{},"Tạo ",[440,1835,1836],{},"NpgsqlCommand(sql, conn, tx)"," — mỗi command gắn với transaction.",[505,1839,1840,1843],{},[440,1841,1842],{},"CommitAsync()"," — lưu toàn bộ thay đổi.",[505,1845,1846,1847,1850],{},"Nếu lỗi → ",[440,1848,1849],{},"RollbackAsync()"," — huỷ tất cả.",[427,1852,1854],{"id":1853},"_6-gọi-postgresql-function","6. Gọi PostgreSQL Function",[432,1856,1857,1858,565],{},"PostgreSQL function trả về giá trị, gọi qua ",[440,1859,1860],{},"SELECT function_name($1, $2)",[450,1862,1866],{"className":1863,"code":1864,"language":1865,"meta":455,"style":455},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- Tạo function trong PostgreSQL\nCREATE OR REPLACE FUNCTION get_student_count(begin_date DATE, end_date DATE)\nRETURNS INT\nLANGUAGE plpgsql\nAS $$\nDECLARE\n    student_count INTEGER;\nBEGIN\n    SELECT COUNT(*) INTO student_count\n    FROM students\n    WHERE registration_date BETWEEN begin_date AND end_date;\n\n    RETURN student_count;\nEND;\n$$;\n","sql",[440,1867,1868,1873,1878,1883,1888,1893,1898,1903,1908,1913,1918,1923,1927,1932,1937],{"__ignoreMap":455},[459,1869,1870],{"class":461,"line":462},[459,1871,1872],{},"-- Tạo function trong PostgreSQL\n",[459,1874,1875],{"class":461,"line":479},[459,1876,1877],{},"CREATE OR REPLACE FUNCTION get_student_count(begin_date DATE, end_date DATE)\n",[459,1879,1880],{"class":461,"line":491},[459,1881,1882],{},"RETURNS INT\n",[459,1884,1885],{"class":461,"line":618},[459,1886,1887],{},"LANGUAGE plpgsql\n",[459,1889,1890],{"class":461,"line":624},[459,1891,1892],{},"AS $$\n",[459,1894,1895],{"class":461,"line":694},[459,1896,1897],{},"DECLARE\n",[459,1899,1900],{"class":461,"line":699},[459,1901,1902],{},"    student_count INTEGER;\n",[459,1904,1905],{"class":461,"line":705},[459,1906,1907],{},"BEGIN\n",[459,1909,1910],{"class":461,"line":711},[459,1911,1912],{},"    SELECT COUNT(*) INTO student_count\n",[459,1914,1915],{"class":461,"line":717},[459,1916,1917],{},"    FROM students\n",[459,1919,1920],{"class":461,"line":723},[459,1921,1922],{},"    WHERE registration_date BETWEEN begin_date AND end_date;\n",[459,1924,1925],{"class":461,"line":729},[459,1926,677],{"emptyLinePlaceholder":676},[459,1928,1929],{"class":461,"line":734},[459,1930,1931],{},"    RETURN student_count;\n",[459,1933,1934],{"class":461,"line":740},[459,1935,1936],{},"END;\n",[459,1938,1939],{"class":461,"line":746},[459,1940,1941],{},"$$;\n",[450,1943,1945],{"className":662,"code":1944,"language":664,"meta":455,"style":455},"\u002F\u002F Gọi function từ C#\nvar beginDate = new DateOnly(2026, 5, 10);\nvar endDate = new DateOnly(2026, 5, 15);\n\nawait using var dataSource = NpgsqlDataSource.Create(connectionString);\n\nawait using var cmd = dataSource.CreateCommand(\"SELECT get_student_count($1, $2)\");\n\ncmd.Parameters.AddWithValue(beginDate);\ncmd.Parameters.AddWithValue(endDate);\n\nawait using var reader = await cmd.ExecuteReaderAsync();\n\nif (await reader.ReadAsync())\n{\n    var studentCount = reader.GetInt32(0);\n    Console.WriteLine($\"Students registered between {beginDate} and {endDate}: {studentCount}\");\n}\n",[440,1946,1947,1952,1957,1962,1966,1970,1974,1979,1983,1988,1993,1997,2001,2005,2010,2014,2019,2024],{"__ignoreMap":455},[459,1948,1949],{"class":461,"line":462},[459,1950,1951],{},"\u002F\u002F Gọi function từ C#\n",[459,1953,1954],{"class":461,"line":479},[459,1955,1956],{},"var beginDate = new DateOnly(2026, 5, 10);\n",[459,1958,1959],{"class":461,"line":491},[459,1960,1961],{},"var endDate = new DateOnly(2026, 5, 15);\n",[459,1963,1964],{"class":461,"line":618},[459,1965,677],{"emptyLinePlaceholder":676},[459,1967,1968],{"class":461,"line":624},[459,1969,889],{},[459,1971,1972],{"class":461,"line":694},[459,1973,677],{"emptyLinePlaceholder":676},[459,1975,1976],{"class":461,"line":699},[459,1977,1978],{},"await using var cmd = dataSource.CreateCommand(\"SELECT get_student_count($1, $2)\");\n",[459,1980,1981],{"class":461,"line":705},[459,1982,677],{"emptyLinePlaceholder":676},[459,1984,1985],{"class":461,"line":711},[459,1986,1987],{},"cmd.Parameters.AddWithValue(beginDate);\n",[459,1989,1990],{"class":461,"line":717},[459,1991,1992],{},"cmd.Parameters.AddWithValue(endDate);\n",[459,1994,1995],{"class":461,"line":723},[459,1996,677],{"emptyLinePlaceholder":676},[459,1998,1999],{"class":461,"line":729},[459,2000,1118],{},[459,2002,2003],{"class":461,"line":734},[459,2004,677],{"emptyLinePlaceholder":676},[459,2006,2007],{"class":461,"line":740},[459,2008,2009],{},"if (await reader.ReadAsync())\n",[459,2011,2012],{"class":461,"line":746},[459,2013,578],{},[459,2015,2016],{"class":461,"line":751},[459,2017,2018],{},"    var studentCount = reader.GetInt32(0);\n",[459,2020,2021],{"class":461,"line":757},[459,2022,2023],{},"    Console.WriteLine($\"Students registered between {beginDate} and {endDate}: {studentCount}\");\n",[459,2025,2026],{"class":461,"line":762},[459,2027,627],{},[525,2029,2030,2035],{"color":630,"icon":631},[432,2031,2032],{},[435,2033,2034],{},"Function vs Stored Procedure trong PostgreSQL:",[502,2036,2037,2050],{},[505,2038,2039,2042,2043,2046,2047,523],{},[435,2040,2041],{},"Function",": gọi bằng ",[440,2044,2045],{},"SELECT",", trả về giá trị. Dùng ",[440,2048,2049],{},"ExecuteReaderAsync()",[505,2051,2052,2055,2056,2059,2060,523],{},[435,2053,2054],{},"Procedure"," (PG 11+): gọi bằng ",[440,2057,2058],{},"CALL",", không trả về giá trị, có thể COMMIT\u002FROLLBACK trong thân. Dùng ",[440,2061,2062],{},"ExecuteNonQueryAsync()",[427,2064,2066],{"id":2065},"_7-gọi-postgresql-stored-procedure","7. Gọi PostgreSQL Stored Procedure",[450,2068,2070],{"className":1863,"code":2069,"language":1865,"meta":455,"style":455},"-- Tạo stored procedure trong PostgreSQL\nCREATE OR REPLACE PROCEDURE enroll_student(\n    p_student_id INTEGER,\n    p_course_id INTEGER,\n    p_amount DOUBLE PRECISION,\n    p_tax DOUBLE PRECISION,\n    p_invoice_date DATE\n)\nLANGUAGE plpgsql\nAS $$\nBEGIN\n    INSERT INTO enrollments (student_id, course_id, enrolled_date)\n    VALUES (p_student_id, p_course_id, p_invoice_date);\n\n    INSERT INTO invoices (student_id, course_id, amount, tax, invoice_date)\n    VALUES (p_student_id, p_course_id, p_amount, p_tax, p_invoice_date);\nEND;\n$$;\n",[440,2071,2072,2077,2082,2087,2092,2097,2102,2107,2112,2116,2120,2124,2129,2134,2138,2143,2148,2152],{"__ignoreMap":455},[459,2073,2074],{"class":461,"line":462},[459,2075,2076],{},"-- Tạo stored procedure trong PostgreSQL\n",[459,2078,2079],{"class":461,"line":479},[459,2080,2081],{},"CREATE OR REPLACE PROCEDURE enroll_student(\n",[459,2083,2084],{"class":461,"line":491},[459,2085,2086],{},"    p_student_id INTEGER,\n",[459,2088,2089],{"class":461,"line":618},[459,2090,2091],{},"    p_course_id INTEGER,\n",[459,2093,2094],{"class":461,"line":624},[459,2095,2096],{},"    p_amount DOUBLE PRECISION,\n",[459,2098,2099],{"class":461,"line":694},[459,2100,2101],{},"    p_tax DOUBLE PRECISION,\n",[459,2103,2104],{"class":461,"line":699},[459,2105,2106],{},"    p_invoice_date DATE\n",[459,2108,2109],{"class":461,"line":705},[459,2110,2111],{},")\n",[459,2113,2114],{"class":461,"line":711},[459,2115,1887],{},[459,2117,2118],{"class":461,"line":717},[459,2119,1892],{},[459,2121,2122],{"class":461,"line":723},[459,2123,1907],{},[459,2125,2126],{"class":461,"line":729},[459,2127,2128],{},"    INSERT INTO enrollments (student_id, course_id, enrolled_date)\n",[459,2130,2131],{"class":461,"line":734},[459,2132,2133],{},"    VALUES (p_student_id, p_course_id, p_invoice_date);\n",[459,2135,2136],{"class":461,"line":740},[459,2137,677],{"emptyLinePlaceholder":676},[459,2139,2140],{"class":461,"line":746},[459,2141,2142],{},"    INSERT INTO invoices (student_id, course_id, amount, tax, invoice_date)\n",[459,2144,2145],{"class":461,"line":751},[459,2146,2147],{},"    VALUES (p_student_id, p_course_id, p_amount, p_tax, p_invoice_date);\n",[459,2149,2150],{"class":461,"line":757},[459,2151,1936],{},[459,2153,2154],{"class":461,"line":762},[459,2155,1941],{},[450,2157,2159],{"className":662,"code":2158,"language":664,"meta":455,"style":455},"\u002F\u002F Gọi stored procedure từ C#\nvar studentId = 2;\nvar courseId = 2;\nvar amount = 49.99;\nvar tax = 0.05;\nvar invoiceDate = new DateOnly(2026, 7, 8);\n\nawait using var dataSource = NpgsqlDataSource.Create(connectionString);\n\n\u002F\u002F Gọi procedure bằng CALL với positional parameters $1, $2...\nawait using var cmd = dataSource.CreateCommand(\"CALL enroll_student($1, $2, $3, $4, $5)\");\n\ncmd.Parameters.AddWithValue(studentId);\ncmd.Parameters.AddWithValue(courseId);\ncmd.Parameters.AddWithValue(amount);\ncmd.Parameters.AddWithValue(tax);\ncmd.Parameters.AddWithValue(invoiceDate);\n\nawait cmd.ExecuteNonQueryAsync();\nConsole.WriteLine(\"Stored procedure executed successfully.\");\n",[440,2160,2161,2166,2171,2176,2181,2186,2191,2195,2199,2203,2208,2213,2217,2222,2227,2232,2237,2242,2246,2250],{"__ignoreMap":455},[459,2162,2163],{"class":461,"line":462},[459,2164,2165],{},"\u002F\u002F Gọi stored procedure từ C#\n",[459,2167,2168],{"class":461,"line":479},[459,2169,2170],{},"var studentId = 2;\n",[459,2172,2173],{"class":461,"line":491},[459,2174,2175],{},"var courseId = 2;\n",[459,2177,2178],{"class":461,"line":618},[459,2179,2180],{},"var amount = 49.99;\n",[459,2182,2183],{"class":461,"line":624},[459,2184,2185],{},"var tax = 0.05;\n",[459,2187,2188],{"class":461,"line":694},[459,2189,2190],{},"var invoiceDate = new DateOnly(2026, 7, 8);\n",[459,2192,2193],{"class":461,"line":699},[459,2194,677],{"emptyLinePlaceholder":676},[459,2196,2197],{"class":461,"line":705},[459,2198,889],{},[459,2200,2201],{"class":461,"line":711},[459,2202,677],{"emptyLinePlaceholder":676},[459,2204,2205],{"class":461,"line":717},[459,2206,2207],{},"\u002F\u002F Gọi procedure bằng CALL với positional parameters $1, $2...\n",[459,2209,2210],{"class":461,"line":723},[459,2211,2212],{},"await using var cmd = dataSource.CreateCommand(\"CALL enroll_student($1, $2, $3, $4, $5)\");\n",[459,2214,2215],{"class":461,"line":729},[459,2216,677],{"emptyLinePlaceholder":676},[459,2218,2219],{"class":461,"line":734},[459,2220,2221],{},"cmd.Parameters.AddWithValue(studentId);\n",[459,2223,2224],{"class":461,"line":740},[459,2225,2226],{},"cmd.Parameters.AddWithValue(courseId);\n",[459,2228,2229],{"class":461,"line":746},[459,2230,2231],{},"cmd.Parameters.AddWithValue(amount);\n",[459,2233,2234],{"class":461,"line":751},[459,2235,2236],{},"cmd.Parameters.AddWithValue(tax);\n",[459,2238,2239],{"class":461,"line":757},[459,2240,2241],{},"cmd.Parameters.AddWithValue(invoiceDate);\n",[459,2243,2244],{"class":461,"line":762},[459,2245,677],{"emptyLinePlaceholder":676},[459,2247,2248],{"class":461,"line":768},[459,2249,984],{},[459,2251,2252],{"class":461,"line":774},[459,2253,2254],{},"Console.WriteLine(\"Stored procedure executed successfully.\");\n",[525,2256,2257,2262],{"color":860,"icon":528},[432,2258,531,2259],{},[435,2260,2261],{},"Khác biệt PostgreSQL vs SQL Server:",[502,2263,2264,2284,2293],{},[505,2265,2266,2267,1087,2270,2273,2274,2277,2278,2281,2282,523],{},"Postgres dùng ",[435,2268,2269],{},"positional parameters",[440,2271,2272],{},"$1",", ",[440,2275,2276],{},"$2","...) thay vì named parameters (",[440,2279,2280],{},"@name",") trong ",[440,2283,2058],{},[505,2285,2266,2286,2289,2290,655],{},[440,2287,2288],{},"CALL procedure_name(...)"," thay vì ",[440,2291,2292],{},"EXEC procedure_name",[505,2294,647,2295,2298,2299,2302],{},[440,2296,2297],{},"CommandType.StoredProcedure"," — luôn là text command (",[440,2300,2301],{},"CommandType.Text"," mặc định).",[427,2304,2306],{"id":2305},"_8-pattern-tổ-chức-code-khuyên-dùng","8. Pattern tổ chức code khuyên dùng",[445,2308,2310],{"id":2309},"dependency-injection-đăng-ký-npgsqldatasource","Dependency Injection — đăng ký NpgsqlDataSource",[450,2312,2314],{"className":662,"code":2313,"language":664,"meta":455,"style":455},"\u002F\u002F Program.cs — .NET 8+\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddSingleton\u003CNpgsqlDataSource>(sp =>\n{\n    var connectionString = builder.Configuration.GetConnectionString(\"DefaultConnection\");\n    return NpgsqlDataSource.Create(connectionString);\n});\n\n\u002F\u002F Dùng trong controller \u002F service\npublic class StudentRepository\n{\n    private readonly NpgsqlDataSource _dataSource;\n\n    public StudentRepository(NpgsqlDataSource dataSource)\n    {\n        _dataSource = dataSource;\n    }\n\n    public async Task\u003CStudent?> GetByIdAsync(int id)\n    {\n        await using var cmd = _dataSource.CreateCommand(\n            \"SELECT id, first_name, last_name, email FROM students WHERE id = $1\");\n\n        cmd.Parameters.AddWithValue(id);\n\n        await using var reader = await cmd.ExecuteReaderAsync();\n\n        if (await reader.ReadAsync())\n        {\n            return new Student(\n                reader.GetInt32(0),\n                reader.GetString(1),\n                reader.GetString(2),\n                reader.GetString(3)\n            );\n        }\n        return null;\n    }\n}\n",[440,2315,2316,2321,2326,2330,2335,2339,2344,2349,2354,2358,2363,2368,2372,2377,2381,2386,2390,2395,2399,2403,2408,2412,2417,2422,2426,2431,2435,2440,2444,2449,2453,2458,2463,2468,2473,2478,2483,2487,2492,2496],{"__ignoreMap":455},[459,2317,2318],{"class":461,"line":462},[459,2319,2320],{},"\u002F\u002F Program.cs — .NET 8+\n",[459,2322,2323],{"class":461,"line":479},[459,2324,2325],{},"var builder = WebApplication.CreateBuilder(args);\n",[459,2327,2328],{"class":461,"line":491},[459,2329,677],{"emptyLinePlaceholder":676},[459,2331,2332],{"class":461,"line":618},[459,2333,2334],{},"builder.Services.AddSingleton\u003CNpgsqlDataSource>(sp =>\n",[459,2336,2337],{"class":461,"line":624},[459,2338,578],{},[459,2340,2341],{"class":461,"line":694},[459,2342,2343],{},"    var connectionString = builder.Configuration.GetConnectionString(\"DefaultConnection\");\n",[459,2345,2346],{"class":461,"line":699},[459,2347,2348],{},"    return NpgsqlDataSource.Create(connectionString);\n",[459,2350,2351],{"class":461,"line":705},[459,2352,2353],{},"});\n",[459,2355,2356],{"class":461,"line":711},[459,2357,677],{"emptyLinePlaceholder":676},[459,2359,2360],{"class":461,"line":717},[459,2361,2362],{},"\u002F\u002F Dùng trong controller \u002F service\n",[459,2364,2365],{"class":461,"line":723},[459,2366,2367],{},"public class StudentRepository\n",[459,2369,2370],{"class":461,"line":729},[459,2371,578],{},[459,2373,2374],{"class":461,"line":734},[459,2375,2376],{},"    private readonly NpgsqlDataSource _dataSource;\n",[459,2378,2379],{"class":461,"line":740},[459,2380,677],{"emptyLinePlaceholder":676},[459,2382,2383],{"class":461,"line":746},[459,2384,2385],{},"    public StudentRepository(NpgsqlDataSource dataSource)\n",[459,2387,2388],{"class":461,"line":751},[459,2389,708],{},[459,2391,2392],{"class":461,"line":757},[459,2393,2394],{},"        _dataSource = dataSource;\n",[459,2396,2397],{"class":461,"line":762},[459,2398,743],{},[459,2400,2401],{"class":461,"line":768},[459,2402,677],{"emptyLinePlaceholder":676},[459,2404,2405],{"class":461,"line":774},[459,2406,2407],{},"    public async Task\u003CStudent?> GetByIdAsync(int id)\n",[459,2409,2410],{"class":461,"line":780},[459,2411,708],{},[459,2413,2414],{"class":461,"line":786},[459,2415,2416],{},"        await using var cmd = _dataSource.CreateCommand(\n",[459,2418,2419],{"class":461,"line":792},[459,2420,2421],{},"            \"SELECT id, first_name, last_name, email FROM students WHERE id = $1\");\n",[459,2423,2424],{"class":461,"line":798},[459,2425,677],{"emptyLinePlaceholder":676},[459,2427,2428],{"class":461,"line":804},[459,2429,2430],{},"        cmd.Parameters.AddWithValue(id);\n",[459,2432,2433],{"class":461,"line":809},[459,2434,677],{"emptyLinePlaceholder":676},[459,2436,2437],{"class":461,"line":1456},[459,2438,2439],{},"        await using var reader = await cmd.ExecuteReaderAsync();\n",[459,2441,2442],{"class":461,"line":1461},[459,2443,677],{"emptyLinePlaceholder":676},[459,2445,2446],{"class":461,"line":1467},[459,2447,2448],{},"        if (await reader.ReadAsync())\n",[459,2450,2451],{"class":461,"line":1473},[459,2452,777],{},[459,2454,2455],{"class":461,"line":1479},[459,2456,2457],{},"            return new Student(\n",[459,2459,2460],{"class":461,"line":1484},[459,2461,2462],{},"                reader.GetInt32(0),\n",[459,2464,2465],{"class":461,"line":1490},[459,2466,2467],{},"                reader.GetString(1),\n",[459,2469,2470],{"class":461,"line":1495},[459,2471,2472],{},"                reader.GetString(2),\n",[459,2474,2475],{"class":461,"line":1501},[459,2476,2477],{},"                reader.GetString(3)\n",[459,2479,2480],{"class":461,"line":1506},[459,2481,2482],{},"            );\n",[459,2484,2485],{"class":461,"line":1512},[459,2486,795],{},[459,2488,2489],{"class":461,"line":1517},[459,2490,2491],{},"        return null;\n",[459,2493,2494],{"class":461,"line":1523},[459,2495,743],{},[459,2497,2498],{"class":461,"line":1528},[459,2499,627],{},[445,2501,2503],{"id":2502},"dapper-npgsql-cho-team-thích-micro-orm","Dapper + Npgsql (cho team thích micro-ORM)",[450,2505,2507],{"className":452,"code":2506,"language":454,"meta":455,"style":455},"dotnet add package Dapper\n",[440,2508,2509],{"__ignoreMap":455},[459,2510,2511,2513,2515,2517],{"class":461,"line":462},[459,2512,466],{"class":465},[459,2514,470],{"class":469},[459,2516,473],{"class":469},[459,2518,2519],{"class":469}," Dapper\n",[450,2521,2523],{"className":662,"code":2522,"language":664,"meta":455,"style":455},"using Dapper;\n\n\u002F\u002F Dapper dùng trực tiếp NpgsqlConnection\nawait using var conn = new NpgsqlConnection(connectionString);\n\n\u002F\u002F Query — tự map sang object\nvar students = await conn.QueryAsync\u003CStudent>(\n    \"SELECT * FROM students WHERE registration_date >= @date\",\n    new { date = new DateOnly(2026, 1, 1) }\n);\n\n\u002F\u002F Execute — INSERT\u002FUPDATE\u002FDELETE\nvar rowsAffected = await conn.ExecuteAsync(\n    \"UPDATE students SET email = @Email WHERE id = @Id\",\n    new { Email = \"new@example.com\", Id = 1 }\n);\n",[440,2524,2525,2530,2534,2539,2543,2547,2552,2557,2562,2567,2572,2576,2581,2586,2591,2596],{"__ignoreMap":455},[459,2526,2527],{"class":461,"line":462},[459,2528,2529],{},"using Dapper;\n",[459,2531,2532],{"class":461,"line":479},[459,2533,677],{"emptyLinePlaceholder":676},[459,2535,2536],{"class":461,"line":491},[459,2537,2538],{},"\u002F\u002F Dapper dùng trực tiếp NpgsqlConnection\n",[459,2540,2541],{"class":461,"line":618},[459,2542,843],{},[459,2544,2545],{"class":461,"line":624},[459,2546,677],{"emptyLinePlaceholder":676},[459,2548,2549],{"class":461,"line":694},[459,2550,2551],{},"\u002F\u002F Query — tự map sang object\n",[459,2553,2554],{"class":461,"line":699},[459,2555,2556],{},"var students = await conn.QueryAsync\u003CStudent>(\n",[459,2558,2559],{"class":461,"line":705},[459,2560,2561],{},"    \"SELECT * FROM students WHERE registration_date >= @date\",\n",[459,2563,2564],{"class":461,"line":711},[459,2565,2566],{},"    new { date = new DateOnly(2026, 1, 1) }\n",[459,2568,2569],{"class":461,"line":717},[459,2570,2571],{},");\n",[459,2573,2574],{"class":461,"line":723},[459,2575,677],{"emptyLinePlaceholder":676},[459,2577,2578],{"class":461,"line":729},[459,2579,2580],{},"\u002F\u002F Execute — INSERT\u002FUPDATE\u002FDELETE\n",[459,2582,2583],{"class":461,"line":734},[459,2584,2585],{},"var rowsAffected = await conn.ExecuteAsync(\n",[459,2587,2588],{"class":461,"line":740},[459,2589,2590],{},"    \"UPDATE students SET email = @Email WHERE id = @Id\",\n",[459,2592,2593],{"class":461,"line":746},[459,2594,2595],{},"    new { Email = \"new@example.com\", Id = 1 }\n",[459,2597,2598],{"class":461,"line":751},[459,2599,2571],{},[445,2601,2603],{"id":2602},"entity-framework-core-npgsql","Entity Framework Core + Npgsql",[450,2605,2607],{"className":452,"code":2606,"language":454,"meta":455,"style":455},"dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL\n",[440,2608,2609],{"__ignoreMap":455},[459,2610,2611,2613,2615,2617],{"class":461,"line":462},[459,2612,466],{"class":465},[459,2614,470],{"class":469},[459,2616,473],{"class":469},[459,2618,2619],{"class":469}," Npgsql.EntityFrameworkCore.PostgreSQL\n",[450,2621,2623],{"className":662,"code":2622,"language":664,"meta":455,"style":455},"\u002F\u002F DbContext\npublic class AppDbContext : DbContext\n{\n    public DbSet\u003CStudent> Students { get; set; }\n\n    protected override void OnConfiguring(DbContextOptionsBuilder options)\n    {\n        options.UseNpgsql(connectionString);\n    }\n}\n",[440,2624,2625,2630,2635,2639,2644,2648,2653,2657,2662,2666],{"__ignoreMap":455},[459,2626,2627],{"class":461,"line":462},[459,2628,2629],{},"\u002F\u002F DbContext\n",[459,2631,2632],{"class":461,"line":479},[459,2633,2634],{},"public class AppDbContext : DbContext\n",[459,2636,2637],{"class":461,"line":491},[459,2638,578],{},[459,2640,2641],{"class":461,"line":618},[459,2642,2643],{},"    public DbSet\u003CStudent> Students { get; set; }\n",[459,2645,2646],{"class":461,"line":624},[459,2647,677],{"emptyLinePlaceholder":676},[459,2649,2650],{"class":461,"line":694},[459,2651,2652],{},"    protected override void OnConfiguring(DbContextOptionsBuilder options)\n",[459,2654,2655],{"class":461,"line":699},[459,2656,708],{},[459,2658,2659],{"class":461,"line":705},[459,2660,2661],{},"        options.UseNpgsql(connectionString);\n",[459,2663,2664],{"class":461,"line":711},[459,2665,743],{},[459,2667,2668],{"class":461,"line":717},[459,2669,627],{},[525,2671,2672,2677],{"color":527,"icon":631},[432,2673,2674],{},[435,2675,2676],{},"Chọn library nào?",[2678,2679,2680,2693],"table",{},[2681,2682,2683],"thead",{},[2684,2685,2686,2690],"tr",{},[2687,2688,2689],"th",{},"Library",[2687,2691,2692],{},"Khi nào",[2694,2695,2696,2707,2717],"tbody",{},[2684,2697,2698,2704],{},[2699,2700,2701],"td",{},[435,2702,2703],{},"Npgsql thô (ADO.NET)",[2699,2705,2706],{},"Performance critical, cần control hoàn toàn SQL",[2684,2708,2709,2714],{},[2699,2710,2711],{},[435,2712,2713],{},"Dapper",[2699,2715,2716],{},"Muốn nhanh hơn EF, vẫn map object, thích viết SQL tay",[2684,2718,2719,2724],{},[2699,2720,2721],{},[435,2722,2723],{},"EF Core + Npgsql",[2699,2725,2726],{},"Code-first, migration, LINQ, team quen EF",[427,2728,2730],{"id":2729},"_9-kiểu-dữ-liệu-postgresql-mapping-với-c","9. Kiểu dữ liệu PostgreSQL mapping với C#",[2678,2732,2733,2742],{},[2681,2734,2735],{},[2684,2736,2737,2739],{},[2687,2738,198],{},[2687,2740,2741],{},"C#",[2694,2743,2744,2759,2771,2783,2798,2810,2822,2834,2849,2862,2874,2892,2904,2923,2935,2950],{},[2684,2745,2746,2754],{},[2699,2747,2748,651,2751],{},[440,2749,2750],{},"INTEGER",[440,2752,2753],{},"INT",[2699,2755,2756],{},[440,2757,2758],{},"int",[2684,2760,2761,2766],{},[2699,2762,2763],{},[440,2764,2765],{},"BIGINT",[2699,2767,2768],{},[440,2769,2770],{},"long",[2684,2772,2773,2778],{},[2699,2774,2775],{},[440,2776,2777],{},"SMALLINT",[2699,2779,2780],{},[440,2781,2782],{},"short",[2684,2784,2785,2793],{},[2699,2786,2787,651,2790],{},[440,2788,2789],{},"NUMERIC",[440,2791,2792],{},"DECIMAL",[2699,2794,2795],{},[440,2796,2797],{},"decimal",[2684,2799,2800,2805],{},[2699,2801,2802],{},[440,2803,2804],{},"REAL",[2699,2806,2807],{},[440,2808,2809],{},"float",[2684,2811,2812,2817],{},[2699,2813,2814],{},[440,2815,2816],{},"DOUBLE PRECISION",[2699,2818,2819],{},[440,2820,2821],{},"double",[2684,2823,2824,2829],{},[2699,2825,2826],{},[440,2827,2828],{},"BOOLEAN",[2699,2830,2831],{},[440,2832,2833],{},"bool",[2684,2835,2836,2844],{},[2699,2837,2838,651,2841],{},[440,2839,2840],{},"VARCHAR(n)",[440,2842,2843],{},"TEXT",[2699,2845,2846],{},[440,2847,2848],{},"string",[2684,2850,2851,2856],{},[2699,2852,2853],{},[440,2854,2855],{},"DATE",[2699,2857,2858,2861],{},[440,2859,2860],{},"DateOnly"," (.NET 6+)",[2684,2863,2864,2869],{},[2699,2865,2866],{},[440,2867,2868],{},"TIME",[2699,2870,2871,2861],{},[440,2872,2873],{},"TimeOnly",[2684,2875,2876,2884],{},[2699,2877,2878,651,2881],{},[440,2879,2880],{},"TIMESTAMP",[440,2882,2883],{},"TIMESTAMPTZ",[2699,2885,2886,651,2889],{},[440,2887,2888],{},"DateTime",[440,2890,2891],{},"DateTimeOffset",[2684,2893,2894,2899],{},[2699,2895,2896],{},[440,2897,2898],{},"UUID",[2699,2900,2901],{},[440,2902,2903],{},"Guid",[2684,2905,2906,2914],{},[2699,2907,2908,651,2911],{},[440,2909,2910],{},"JSON",[440,2912,2913],{},"JSONB",[2699,2915,2916,2918,2919,2922],{},[440,2917,2848],{}," (hoặc ",[440,2920,2921],{},"JsonDocument"," \u002F custom type)",[2684,2924,2925,2930],{},[2699,2926,2927],{},[440,2928,2929],{},"BYTEA",[2699,2931,2932],{},[440,2933,2934],{},"byte[]",[2684,2936,2937,2942],{},[2699,2938,2939],{},[440,2940,2941],{},"INT[]",[2699,2943,2944,651,2947],{},[440,2945,2946],{},"int[]",[440,2948,2949],{},"List\u003Cint>",[2684,2951,2952,2957],{},[2699,2953,2954],{},[440,2955,2956],{},"TEXT[]",[2699,2958,2959,651,2962],{},[440,2960,2961],{},"string[]",[440,2963,2964],{},"List\u003Cstring>",[427,2966,2968],{"id":2967},"_10-best-practices","10. Best practices",[525,2970,2972],{"color":2971,"icon":383},"success",[1823,2973,2974,2984,2990,2993,2999,3006,3009,3012,3019,3026],{},[505,2975,2976,2977,2979,2980,2983],{},"✅ Dùng ",[440,2978,894],{}," (singleton, thread-safe) — không new ",[440,2981,2982],{},"NpgsqlConnection"," thủ công mỗi lần.",[505,2985,2986,2987,2989],{},"✅ Luôn ",[440,2988,866],{}," cho connection, command, reader — tránh leak resource.",[505,2991,2992],{},"✅ Parameterized query 100% — không bao giờ nối chuỗi SQL.",[505,2994,2976,2995,2998],{},[440,2996,2997],{},"RETURNING"," clause để lấy giá trị sau INSERT\u002FUPDATE.",[505,3000,3001,3002,3005],{},"✅ Bắt ",[440,3003,3004],{},"NpgsqlException"," riêng — xử lý lỗi PostgreSQL cụ thể.",[505,3007,3008],{},"✅ Transaction có try-catch + rollback rõ ràng.",[505,3010,3011],{},"✅ Pooling connection (bật mặc định trong Npgsql) — không cần tự quản lý.",[505,3013,3014,3015,3018],{},"✅ Với batch insert lớn, dùng ",[440,3016,3017],{},"COPY"," (binary protocol) thay vì INSERT từng dòng — nhanh hơn 10-100x.",[505,3020,3021,3022,3025],{},"✅ Set ",[440,3023,3024],{},"CommandTimeout"," cho query dài — default 30s có thể không đủ.",[505,3027,2976,3028,651,3030,3032,3033,3035],{},[440,3029,2860],{},[440,3031,2873],{}," (.NET 6+) thay vì ",[440,3034,2888],{}," cho cột DATE \u002F TIME.",[525,3037,3039,3040],{"color":527,"icon":3038},"i-lucide-arrow-right","Tiếp theo: ",[3041,3042,3043],"a",{"href":229},"MySQL — Giới thiệu và cài đặt",[3045,3046,3047],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":455,"searchDepth":479,"depth":479,"links":3049},[3050,3053,3059,3066,3067,3068,3069,3070,3075,3076],{"id":429,"depth":479,"text":430,"children":3051},[3052],{"id":447,"depth":491,"text":448},{"id":554,"depth":479,"text":555,"children":3054},[3055,3056,3057,3058],{"id":558,"depth":491,"text":559},{"id":658,"depth":491,"text":659},{"id":814,"depth":491,"text":815},{"id":874,"depth":491,"text":875},{"id":917,"depth":479,"text":918,"children":3060},[3061,3062,3063,3064,3065],{"id":921,"depth":491,"text":922},{"id":996,"depth":491,"text":997},{"id":1094,"depth":491,"text":1095},{"id":1206,"depth":491,"text":1207},{"id":1266,"depth":491,"text":1267},{"id":1305,"depth":479,"text":1306},{"id":1585,"depth":479,"text":1586},{"id":1853,"depth":479,"text":1854},{"id":2065,"depth":479,"text":2066},{"id":2305,"depth":479,"text":2306,"children":3071},[3072,3073,3074],{"id":2309,"depth":491,"text":2310},{"id":2502,"depth":491,"text":2503},{"id":2602,"depth":491,"text":2603},{"id":2729,"depth":479,"text":2730},{"id":2967,"depth":479,"text":2968},"Hướng dẫn toàn diện kết nối PostgreSQL từ C# dùng Npgsql — CRUD, transaction, gọi function\u002Fstored procedure, import CSV. Dành cho dev .NET.","md",null,{},{"title":219,"icon":96},{"title":422,"description":3077},"q4-kzmi8WXZfDnquknkPb91wLzxn0iyoO4vL0bFaCmE",[3085,3087],{"title":193,"path":216,"stem":217,"description":3086,"icon":196,"children":-1},"70+ câu hỏi phỏng vấn Postgres cho dev backend \u002F fullstack — đáp án ngắn, có dẫn chiếu Postgres 18 & 19.",{"title":173,"path":229,"stem":230,"description":3088,"icon":176,"children":-1},"MySQL — RDBMS open-source phổ biến nhất. Bản 9.7 LTS mới (04\u002F2026, đến ~2034) với Hypergraph Optimizer vào Community, PBKDF2+SHA512, JavaScript in-database.",1783490366127]