|
| 1 | +--- |
| 2 | +title: C# app to connect and query Hyperscale (Citus) |
| 3 | +description: Learn to query Hyperscale (Citus) using C# |
| 4 | +ms.author: sasriram |
| 5 | +author: saimicrosoft |
| 6 | +ms.service: postgresql |
| 7 | +ms.subservice: hyperscale-citus |
| 8 | +ms.topic: how-to |
| 9 | +ms.date: 06/20/2022 |
| 10 | +--- |
| 11 | + |
| 12 | +# C# app to connect and query Hyperscale (Citus) |
| 13 | + |
| 14 | +[!INCLUDE[applies-to-postgresql-hyperscale](../includes/applies-to-postgresql-hyperscale.md)] |
| 15 | + |
| 16 | +In this document, you'll learn how to connect to a Hyperscale (Citus) database using a C# application. You'll see how to use SQL statements to query, insert, update, and delete data in the database. The steps in this article assume that you're familiar with developing using C#, and are new to working with Hyperscale (Citus). |
| 17 | + |
| 18 | +> [!TIP] |
| 19 | +> |
| 20 | +> The process of creating a C# app with Hyperscale (Citus) is the same as working with ordinary PostgreSQL. |
| 21 | +
|
| 22 | +## Prerequisites |
| 23 | + |
| 24 | +* An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free) |
| 25 | +* Create a Hyperscale (Citus) server group using this link [Create Hyperscale (Citus) server group](quickstart-create-portal.md) |
| 26 | +* Install the [.NET SDK](https://dotnet.microsoft.com/download) for your platform (Windows, Ubuntu Linux, or macOS) for your platform. |
| 27 | +* Install [Visual Studio](https://www.visualstudio.com/downloads/) to build your project. |
| 28 | +* Install the [Npgsql](https://www.nuget.org/packages/Npgsql/) NuGet package in Visual Studio. |
| 29 | + |
| 30 | +## Get database connection information |
| 31 | + |
| 32 | +To get the database credentials, you can use the **Connection strings** tab in the Azure portal. See below screenshot. |
| 33 | + |
| 34 | + |
| 35 | + |
| 36 | +## Step 1: Connect, create table, and insert data |
| 37 | + |
| 38 | +Use the following code to connect and load the data using CREATE TABLE and INSERT INTO SQL statements. The code uses these `NpgsqlCommand` class methods: |
| 39 | + |
| 40 | +* [Open()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlConnection.html#Npgsql_NpgsqlConnection_Open) to establish a connection to Hyperscale (Citus), |
| 41 | +* [CreateCommand()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlConnection.html#Npgsql_NpgsqlConnection_CreateCommand) to set the CommandText property, |
| 42 | +* [ExecuteNonQuery()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlCommand.html#Npgsql_NpgsqlCommand_ExecuteNonQuery) to run database commands. |
| 43 | + |
| 44 | +```csharp |
| 45 | +using System; |
| 46 | +using Npgsql; |
| 47 | +namespace Driver |
| 48 | +{ |
| 49 | + public class AzurePostgresCreate |
| 50 | + { |
| 51 | + |
| 52 | + static void Main(string[] args) |
| 53 | + { |
| 54 | + // Replace below argument with connection string from portal. |
| 55 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host> Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 56 | + |
| 57 | + connStr.TrustServerCertificate = true; |
| 58 | + |
| 59 | + using (var conn = new NpgsqlConnection(connStr.ToString())) |
| 60 | + { |
| 61 | + Console.Out.WriteLine("Opening connection"); |
| 62 | + conn.Open(); |
| 63 | + using (var command = new NpgsqlCommand("DROP TABLE IF EXISTS pharmacy;", conn)) |
| 64 | + { |
| 65 | + command.ExecuteNonQuery(); |
| 66 | + Console.Out.WriteLine("Finished dropping table (if existed)"); |
| 67 | + } |
| 68 | + using (var command = new NpgsqlCommand("CREATE TABLE pharmacy (pharmacy_id integer ,pharmacy_name text,city text,state text,zip_code integer);", conn)) |
| 69 | + { |
| 70 | + command.ExecuteNonQuery(); |
| 71 | + Console.Out.WriteLine("Finished creating table"); |
| 72 | + } |
| 73 | + using (var command = new NpgsqlCommand("CREATE INDEX idx_pharmacy_id ON pharmacy(pharmacy_id);", conn)) |
| 74 | + { |
| 75 | + command.ExecuteNonQuery(); |
| 76 | + Console.Out.WriteLine("Finished creating index"); |
| 77 | + } |
| 78 | + using (var command = new NpgsqlCommand("INSERT INTO pharmacy (pharmacy_id,pharmacy_name,city,state,zip_code) VALUES (@n1, @q1, @a, @b, @c)", conn)) |
| 79 | + { |
| 80 | + command.Parameters.AddWithValue("n1", 0); |
| 81 | + command.Parameters.AddWithValue("q1", "Target"); |
| 82 | + command.Parameters.AddWithValue("a", "Sunnyvale"); |
| 83 | + command.Parameters.AddWithValue("b", "California"); |
| 84 | + command.Parameters.AddWithValue("c", 94001); |
| 85 | + int nRows = command.ExecuteNonQuery(); |
| 86 | + Console.Out.WriteLine(String.Format("Number of rows inserted={0}", nRows)); |
| 87 | + } |
| 88 | + |
| 89 | + } |
| 90 | + Console.WriteLine("Press RETURN to exit"); |
| 91 | + Console.ReadLine(); |
| 92 | + } |
| 93 | + } |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +## Step 2: Use the super power of distributed tables |
| 98 | + |
| 99 | +Hyperscale (Citus) gives you [the super power of distributing tables](overview.md#the-superpower-of-distributed-tables) across multiple nodes for scalability. The command below enables you to distribute a table. You can learn more about `create_distributed_table` and the distribution column [here](howto-build-scalable-apps-concepts.md#distribution-column-also-known-as-shard-key). |
| 100 | + |
| 101 | +> [!TIP] |
| 102 | +> |
| 103 | +> Distributing your tables is optional if you are using the Basic Tier of Hyperscale (Citus), which is a single-node server group. |
| 104 | +
|
| 105 | +```csharp |
| 106 | +using System; |
| 107 | +using Npgsql; |
| 108 | +namespace Driver |
| 109 | +{ |
| 110 | + public class AzurePostgresCreate |
| 111 | + { |
| 112 | + |
| 113 | + static void Main(string[] args) |
| 114 | + { |
| 115 | + // Replace below argument with connection string from portal. |
| 116 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 117 | + |
| 118 | + connStr.TrustServerCertificate = true; |
| 119 | + |
| 120 | + using (var conn = new NpgsqlConnection(connStr.ToString())) |
| 121 | + { |
| 122 | + Console.Out.WriteLine("Opening connection"); |
| 123 | + conn.Open(); |
| 124 | + using (var command = new NpgsqlCommand("select create_distributed_table('pharmacy','pharmacy_id');", conn)) |
| 125 | + { |
| 126 | + command.ExecuteNonQuery(); |
| 127 | + Console.Out.WriteLine("Finished distributing the table"); |
| 128 | + } |
| 129 | + |
| 130 | + } |
| 131 | + Console.WriteLine("Press RETURN to exit"); |
| 132 | + Console.ReadLine(); |
| 133 | + } |
| 134 | + } |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +## Step 3: Read data |
| 139 | + |
| 140 | +Use the following code to connect and read the data using a SELECT SQL statement. The code uses these `NpgsqlCommand` class methods: |
| 141 | + |
| 142 | +* [Open()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlConnection.html#Npgsql_NpgsqlConnection_Open) to establish a connection to Hyperscale (Citus). |
| 143 | +* [CreateCommand()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlConnection.html#Npgsql_NpgsqlConnection_CreateCommand) and [ExecuteReader()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlCommand.html#Npgsql_NpgsqlCommand_ExecuteReader) to run the database commands. |
| 144 | +* [Read()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataReader.html#Npgsql_NpgsqlDataReader_Read) to advance to the record in the results. |
| 145 | +* [GetInt32()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataReader.html#Npgsql_NpgsqlDataReader_GetInt32_System_Int32_) and [GetString()](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataReader.html#Npgsql_NpgsqlDataReader_GetString_System_Int32_) to parse the values in the record. |
| 146 | + |
| 147 | +```csharp |
| 148 | +using System; |
| 149 | +using Npgsql; |
| 150 | +namespace Driver |
| 151 | +{ |
| 152 | + public class read |
| 153 | + { |
| 154 | + |
| 155 | + static void Main(string[] args) |
| 156 | + { |
| 157 | + // Replace below argument with connection string from portal. |
| 158 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 159 | + |
| 160 | + connStr.TrustServerCertificate = true; |
| 161 | + |
| 162 | + using (var conn = new NpgsqlConnection(connString)) |
| 163 | + { |
| 164 | + Console.Out.WriteLine("Opening connection"); |
| 165 | + conn.Open(); |
| 166 | + using (var command = new NpgsqlCommand("SELECT * FROM pharmacy", conn)) |
| 167 | + { |
| 168 | + var reader = command.ExecuteReader(); |
| 169 | + while (reader.Read()) |
| 170 | + { |
| 171 | + Console.WriteLine( |
| 172 | + string.Format( |
| 173 | + "Reading from table=({0}, {1}, {2}, {3}, {4})", |
| 174 | + reader.GetInt32(0).ToString(), |
| 175 | + reader.GetString(1), |
| 176 | + reader.GetString(2), |
| 177 | + reader.GetString(3), |
| 178 | + reader.GetInt32(4).ToString() |
| 179 | + ) |
| 180 | + ); |
| 181 | + } |
| 182 | + reader.Close(); |
| 183 | + } |
| 184 | + } |
| 185 | + Console.WriteLine("Press RETURN to exit"); |
| 186 | + Console.ReadLine(); |
| 187 | + } |
| 188 | + } |
| 189 | +} |
| 190 | +``` |
| 191 | + |
| 192 | +## Step 4: Update data |
| 193 | + |
| 194 | +Use the following code to connect and update data using an UPDATE SQL statement. |
| 195 | + |
| 196 | +```csharp |
| 197 | +using System; |
| 198 | +using Npgsql; |
| 199 | +namespace Driver |
| 200 | +{ |
| 201 | + public class AzurePostgresUpdate |
| 202 | + { |
| 203 | + static void Main(string[] args) |
| 204 | + { |
| 205 | + // Replace below argument with connection string from portal. |
| 206 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 207 | + |
| 208 | + connStr.TrustServerCertificate = true; |
| 209 | + |
| 210 | + using (var conn = new NpgsqlConnection(connStr.ToString())) |
| 211 | + { |
| 212 | + Console.Out.WriteLine("Opening connection"); |
| 213 | + conn.Open(); |
| 214 | + using (var command = new NpgsqlCommand("UPDATE pharmacy SET city = @q WHERE pharmacy_id = @n", conn)) |
| 215 | + { |
| 216 | + command.Parameters.AddWithValue("n", 0); |
| 217 | + command.Parameters.AddWithValue("q", "guntur"); |
| 218 | + int nRows = command.ExecuteNonQuery(); |
| 219 | + Console.Out.WriteLine(String.Format("Number of rows updated={0}", nRows)); |
| 220 | + } |
| 221 | + } |
| 222 | + Console.WriteLine("Press RETURN to exit"); |
| 223 | + Console.ReadLine(); |
| 224 | + } |
| 225 | + } |
| 226 | +} |
| 227 | +``` |
| 228 | + |
| 229 | +## Step 5: Delete data |
| 230 | + |
| 231 | +Use the following code to connect and delete data using a DELETE SQL statement. |
| 232 | + |
| 233 | +```csharp |
| 234 | +using System; |
| 235 | +using Npgsql; |
| 236 | +namespace Driver |
| 237 | +{ |
| 238 | + public class AzurePostgresDelete |
| 239 | + { |
| 240 | + |
| 241 | + static void Main(string[] args) |
| 242 | + { |
| 243 | + // Replace below argument with connection string from portal. |
| 244 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 245 | + |
| 246 | + connStr.TrustServerCertificate = true; |
| 247 | + |
| 248 | + using (var conn = new NpgsqlConnection(connStr.ToString())) |
| 249 | + { |
| 250 | + |
| 251 | + Console.Out.WriteLine("Opening connection"); |
| 252 | + conn.Open(); |
| 253 | + using (var command = new NpgsqlCommand("DELETE FROM pharmacy WHERE pharmacy_id = @n", conn)) |
| 254 | + { |
| 255 | + command.Parameters.AddWithValue("n", 0); |
| 256 | + int nRows = command.ExecuteNonQuery(); |
| 257 | + Console.Out.WriteLine(String.Format("Number of rows deleted={0}", nRows)); |
| 258 | + } |
| 259 | + } |
| 260 | + Console.WriteLine("Press RETURN to exit"); |
| 261 | + Console.ReadLine(); |
| 262 | + } |
| 263 | + } |
| 264 | +} |
| 265 | +``` |
| 266 | + |
| 267 | +## COPY command for super fast ingestion |
| 268 | + |
| 269 | +The COPY command can yield [tremendous throughput](https://www.citusdata.com/blog/2016/06/15/copy-postgresql-distributed-tables) while ingesting data into Hyperscale (Citus). The COPY command can ingest data in files, or from micro-batches of data in memory for real-time ingestion. |
| 270 | + |
| 271 | +### COPY command to load data from a file |
| 272 | + |
| 273 | +The following code is an example for copying data from a CSV file to a database table. |
| 274 | + |
| 275 | +It requires the file [pharmacies.csv](https://download.microsoft.com/download/d/8/d/d8d5673e-7cbf-4e13-b3e9-047b05fc1d46/pharmacies.csv). |
| 276 | + |
| 277 | +```csharp |
| 278 | +using Npgsql; |
| 279 | +public class csvtotable |
| 280 | +{ |
| 281 | + |
| 282 | + static void Main(string[] args) |
| 283 | + { |
| 284 | + String sDestinationSchemaAndTableName = "pharmacy"; |
| 285 | + String sFromFilePath = "C:\\Users\\Documents\\pharmacies.csv"; |
| 286 | + |
| 287 | + // Replace below argument with connection string from portal. |
| 288 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 289 | + |
| 290 | + connStr.TrustServerCertificate = true; |
| 291 | + |
| 292 | + NpgsqlConnection conn = new NpgsqlConnection(connStr.ToString()); |
| 293 | + NpgsqlCommand cmd = new NpgsqlCommand(); |
| 294 | + |
| 295 | + conn.Open(); |
| 296 | + |
| 297 | + if (File.Exists(sFromFilePath)) |
| 298 | + { |
| 299 | + using (var writer = conn.BeginTextImport("COPY " + sDestinationSchemaAndTableName + " FROM STDIN WITH(FORMAT CSV, HEADER true,NULL ''); ")) |
| 300 | + { |
| 301 | + foreach (String sLine in File.ReadAllLines(sFromFilePath)) |
| 302 | + { |
| 303 | + writer.WriteLine(sLine); |
| 304 | + } |
| 305 | + } |
| 306 | + Console.WriteLine("csv file data copied sucessfully"); |
| 307 | + } |
| 308 | + } |
| 309 | +} |
| 310 | +``` |
| 311 | + |
| 312 | +### COPY command to load data in-memory |
| 313 | + |
| 314 | +The following code is an example for copying in-memory data to table. |
| 315 | + |
| 316 | +```csharp |
| 317 | +using Npgsql; |
| 318 | +using NpgsqlTypes; |
| 319 | +namespace Driver |
| 320 | +{ |
| 321 | + public class InMemory |
| 322 | + { |
| 323 | + |
| 324 | + static async Task Main(string[] args) |
| 325 | + { |
| 326 | + |
| 327 | + // Replace below argument with connection string from portal. |
| 328 | + var connStr = new NpgsqlConnectionStringBuilder("Server = <host>; Database = citus; Port = 5432; User Id = citus; Password = {your password}; Ssl Mode = Require;"); |
| 329 | + |
| 330 | + connStr.TrustServerCertificate = true; |
| 331 | + |
| 332 | + using (var conn = new NpgsqlConnection(connStr.ToString())) |
| 333 | + { |
| 334 | + conn.Open(); |
| 335 | + var text = new dynamic[] { 0, "Target", "Sunnyvale", "California", 94001 }; |
| 336 | + using (var writer = conn.BeginBinaryImport("COPY pharmacy FROM STDIN (FORMAT BINARY)")) |
| 337 | + { |
| 338 | + writer.StartRow(); |
| 339 | + foreach (var item in text) |
| 340 | + { |
| 341 | + writer.Write(item); |
| 342 | + } |
| 343 | + writer.Complete(); |
| 344 | + } |
| 345 | + Console.WriteLine("in-memory data copied sucessfully"); |
| 346 | + } |
| 347 | + } |
| 348 | + } |
| 349 | +} |
| 350 | +``` |
| 351 | + |
| 352 | +## Next steps |
| 353 | + |
| 354 | +Learn to [build scalable applications](howto-build-scalable-apps-overview.md) |
| 355 | +with Hyperscale (Citus). |
0 commit comments