Hyper-Converged Database (HCD) quickstart for tables (C#)

network_check Beginner
query_builder 15 min

If your data is not fully structured, or if you do not want to use a fixed schema, see the quickstart for collections instead.

This quickstart demonstrates how to create a table schema, insert data with vector embeddings to a table, and perform a vector search to find similar data.

To learn more about vector databases and vector search, see About vector databases and What is Vector Search.

Store your endpoint

The Data API endpoint for your database has the form: http://CLUSTER_HOST:GATEWAY_PORT

  • Replace CLUSTER_HOST with the external IP address of any node in your cluster. To find this, run kubectl get nodes -o wide and use any of the values listed under "EXTERNAL-IP" in the output.

  • Replace GATEWAY_PORT with the port number for your API gateway service. To find this, run kubectl get svc and look for the "PORT(S)" value that corresponds to NodePort.

For this quickstart, store the endpoint in an environment variable:

  • Linux or macOS

  • Windows

export API_ENDPOINT=API_ENDPOINT
set API_ENDPOINT=API_ENDPOINT

Store your username and password

You set a username and password when you create a cluster.

If you didn’t provide superuser credentials when you created your cluster, they were generated automatically and saved in a superuser secret named CLUSTER_NAME-superuser. The CLUSTER_NAME-superuser secret contains both the username and the password.

For this quickstart, store the username and password in environment variables:

  • Linux or macOS

  • Windows

export USERNAME=USERNAME
export PASSWORD=PASSWORD
set USERNAME=USERNAME
set PASSWORD=PASSWORD

Install a client

Install one of the Data API clients to facilitate interactions with the Data API. To use the Data API with tables, you must install client version 2.0.x.

  1. Update to one of the following:

    • .NET version 8 or later

    • .NET Framework 4.6.2 or later

    • .NET Standard 2.1 or later

  2. Install the latest version of the astra-db-csharp package.

    dotnet add package DataStax.AstraDB.DataApi

Connect to your database

The following function will connect to your database.

Copy the file into your project. You don’t need to execute the function now; the subsequent code examples will import and use this function.

QuickstartConnect.cs
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;

namespace Quickstart
{
  public class QuickstartConnect
  {
    public static Database ConnectToDatabase()
    {
      string? endpoint = Environment.GetEnvironmentVariable(
        "API_ENDPOINT"
      ); (1)
      string? username = Environment.GetEnvironmentVariable("USERNAME");
      string? password = Environment.GetEnvironmentVariable("PASSWORD");

      if (
        string.IsNullOrEmpty(endpoint)
        || string.IsNullOrEmpty(username)
        || string.IsNullOrEmpty(password)
      )
      {
        throw new InvalidOperationException(
          "Environment variables API_ENDPOINT, USERNAME, and PASSWORD must be defined"
        );
      }

      // Create an instance of the `DataAPIClient` class
      var client = new DataAPIClient(
        new CommandOptions() { Destination = DataAPIDestination.HCD }
      );

      // Get the database specified by your endpoint and provide the token
      var database = client.GetDatabase(
        endpoint,
        DataAPIClient.UsernamePasswordTokenProvider(username, password)
      );

      Console.WriteLine("Connected to database.");

      return database;
    }
  }
}
1 Store your database’s endpoint, username, and password in environment variables named API_ENDPOINT, USERNAME, and PASSWORD, as instructed in Store your endpoint and Store your username and password.

Create a keyspace

The following code will create a new keyspace in your database.

  1. Copy the code into your project.

  2. If needed, update the import path to the "connect to database" function from the previous section.

  3. Execute the code.

    For information about executing code, refer to the documentation for your programming language.

    Once the code completes, you should see a printed message confirming keyspace creation.

QuickstartCreateKeyspace.cs
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;

namespace Quickstart
{
  public class QuickstartCreateKeyspace
  {
    public static async Task Main()
    {
      var database = QuickstartConnect.ConnectToDatabase(); (1)

      // Get an admin object
      var databaseAdmin = database.GetAdmin();

      // Create a keyspace
      await databaseAdmin.CreateKeyspaceAsync("quickstart_keyspace"); (2)

      Console.WriteLine("Created keyspace.");
    }
  }
}
1 This is the ConnectToDatabase function from the previous section.

To use the function, ensure you stored your database’s endpoint, username, and password in environment variables as instructed in Store your endpoint and Store your username and password.

2 This code creates a keyspace named quickstart_keyspace. If you want to use a different name, change the name before running the code.

Create a table

The following code will create an empty table in your database. The table created here matches the structure of the data that you will insert to the table. After creating the table, the code will index some columns so that you can find and sort data in those columns.

  1. Copy the code into your project.

  2. If needed, update the import path to the "connect to database" function from the previous section.

  3. Execute the code.

    For information about executing code, refer to the documentation for your programming language.

    Once the code completes, you should see a printed message confirming the table creation.

QuickstartCreateTable.cs
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Tables;

namespace Quickstart;

// Define the row type for the table
public class Book
{
  // This table uses a composite primary key
  // with 'title' as the first column in the key
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  // This table uses a composite primary key
  // with 'author' as the second column in the key
  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("number_of_pages")]
  public int? NumberOfPages { get; set; }

  [ColumnName("rating")]
  public float? Rating { get; set; }

  [ColumnName("publication_year")]
  public int? PublicationYear { get; set; }

  [ColumnName("summary")]
  public string? Summary { get; set; }

  [ColumnName("genres")]
  public HashSet<string>? Genres { get; set; }

  [ColumnName("metadata")]
  public Dictionary<string, string>? Metadata { get; set; }

  [ColumnName("is_checked_out")]
  public bool? IsCheckedOut { get; set; }

  [ColumnName("borrower")]
  public string? Borrower { get; set; }

  [ColumnName("due_date")]
  public DateOnly? DueDate { get; set; }

  // This column will store vector embeddings.
  [ColumnVector(dimension: 5)] (1)
  [ColumnName("summary_genres_vector")]
  public float[]? SummaryGenresVector { get; set; }
}

public class QuickstartCreateTable
{
  static async Task Main()
  {
    var database = QuickstartConnect.ConnectToDatabase(); (2)

    var table = await database.CreateTableAsync<Book>(
      "quickstart_table", (3)
      new CreateTableOptions() { Keyspace = "quickstart_keyspace" } (4)
    );

    Console.WriteLine("Created table");

    // Index any columns that you want to sort and filter on.
    await table.CreateIndexAsync("rating_index", (b) => b.Rating);

    await table.CreateIndexAsync(
      "number_of_pages_index",
      (b) => b.NumberOfPages
    );

    await table.CreateVectorIndexAsync(
      "summary_genres_vector_index",
      (b) => b.SummaryGenresVector,
      Builders.TableIndex.Vector(SimilarityMetric.Cosine) (5)
    );

    Console.WriteLine("Indexed columns");
  }
}
1 This column will store 5-dimensional vector data.
2 This is the ConnectToDatabase function from the previous section.

To use the function, ensure you stored your database’s endpoint, username, and password in environment variables as instructed in Store your endpoint and Store your username and password.

3 This code creates a table named quickstart_table. If you want to use a different name, change the name before running the code.
4 This code expects that you have a keyspace named quickstart_keyspace. If you used a different keyspace name in the previous section, update it here.
5 This vector column will use the cosine similarity metric to compare vectors.

Insert data to your table

The following code will insert data from a JSON file into a your table.

  1. Copy the code into your project.

  2. Download the quickstart_dataset.json sample dataset (76 kB). This dataset is a JSON array describing library books.

  3. Replace PATH_TO_DATA_FILE in the code with the path to the dataset.

  4. If needed, update the import path to the "connect to database" function from the previous section.

  5. Execute the code.

    For information about executing code, refer to the documentation for your programming language.

    Once the code completes, you should see a printed message confirming the insertion of 100 rows.

QuickstartInsertToTable.cs
using System.Text.Json.Nodes;
using DataStax.AstraDB.DataApi.Core;

namespace Quickstart
{
  public class QuickstartInsertToTable
  {
    public static async Task Main()
    {
      var database = QuickstartConnect.ConnectToDatabase(); (1)

      var table = database.GetTable<Book>(
        "quickstart_table",
        new GetTableOptions() { Keyspace = "quickstart_keyspace" }
      ); (2)

      var dataFilePath = "PATH_TO_DATA_FILE"; (3)

      // Read the JSON file and parse it into a JSON array
      string rawData = await File.ReadAllTextAsync(dataFilePath);
      JsonArray jsonArray =
        JsonNode.Parse(rawData)?.AsArray() ?? new JsonArray();

      // Assemble the rows to insert
      var rows = new List<Book>();

      foreach (var node in jsonArray)
      {
        if (node is JsonObject obj)
        {
          var row = new Book()
          {
            Title = obj["title"]?.ToString() ?? "",
            Author = obj["author"]?.ToString() ?? "",
            NumberOfPages = obj["number_of_pages"]?.GetValue<int?>(),
            Rating = obj["rating"]?.GetValue<float?>(),
            PublicationYear = obj["publication_year"]?.GetValue<int?>(),
            Summary = obj["summary"]?.ToString(),
            Genres = obj["genres"] is JsonArray genresArray
              ? genresArray.Select(x => x?.ToString() ?? "").ToHashSet()
              : null,
            SummaryGenresVector = obj["summary_genres_vector"]
              is JsonArray vectorArray
              ? vectorArray
                .Select(x => x?.GetValue<float>() ?? 0f)
                .ToArray()
              : null,
            Metadata = obj["metadata"] is JsonObject metadataObject
              ? metadataObject.ToDictionary(
                keyValuePair => keyValuePair.Key,
                keyValuePair => keyValuePair.Value?.ToString() ?? ""
              )
              : null,
            IsCheckedOut = obj["is_checked_out"]?.GetValue<bool?>(),
            Borrower = obj["borrower"]?.ToString(),
            DueDate =
              obj["due_date"]?.GetValue<string>() is string dueDateStr
              && DateOnly.TryParse(dueDateStr, out var parsed)
                ? parsed
                : (DateOnly?)null,
          };

          rows.Add(row);
        }
      }

      // Insert the data
      var result = await table.InsertManyAsync(rows);

      Console.WriteLine($"Inserted {result.InsertedCount} rows");
    }
  }
}
1 This is the ConnectToDatabase function from the previous section.

To use the function, ensure you stored your database’s endpoint, username, and password in environment variables as instructed in Store your endpoint and Store your username and password.

2 This code expects that you have a table named quickstart_table in a keyspace named quickstart_keyspace. If you used a different keyspace or table name in the previous sections, update it here.
3 Replace PATH_TO_DATA_FILE with the path to the JSON data file.

Find data in your table

After you insert data to your table, you can search the data. In addition to traditional database filtering, you can perform a vector search to find data that is most similar to a search vector.

The following code performs three searches on the sample data that you loaded in Insert data to your table.

QuickstartFindRows.cs
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Quickstart
{
  public class QuickstartFindRows
  {
    public static async Task Main()
    {
      var database = QuickstartConnect.ConnectToDatabase(); (1)

      var table = database.GetTable<Book>(
        "quickstart_table",
        new GetTableOptions() { Keyspace = "quickstart_keyspace" }
      ); (2)

      // Find documents that match a filter
      Console.WriteLine(
        "\nFinding books with rating greater than 4.7..."
      );

      var filter = Builders<Book>.TableFilter.Gt(b => b.Rating, 4.7f);
      var ratingCursor = table.Find(
        filter,
        new TableFindOptions<Book>() { Limit = 10 }
      );
      foreach (var row in ratingCursor)
      {
        Console.WriteLine($"{row.Title} is rated {row.Rating}");
      }

      // Perform a vector search to find the closest match to a search vector
      Console.WriteLine("\nUsing vector search to find a book...");

      var findOptions = new TableFindOneOptions<Book>()
      {
        Sort = Builders<Book>.TableSort.Vector(
          b => b.SummaryGenresVector,
          new float[]
          {
            0.016326904f,
            -0.031677246f,
            0.04815674f,
            0.0033435822f,
            0.01876831f,
          }
        ),
      };

      var singleVectorMatch = await table.FindOneAsync(findOptions);

      if (singleVectorMatch != null)
      {
        Console.WriteLine($"{singleVectorMatch.Title} is the best match");
      }

      // Combine a filter, vector search, and projection
      // to find the 3 books with more than 400 pages that are
      // the closest matches to a search vector,
      // and just return the title and author
      Console.WriteLine(
        "\nUsing filters and vector search to find 3 books with more than 400 pages, returning just the title and author..."
      );

      var filter3 = Builders<Book>.TableFilter.Gt(
        b => b.NumberOfPages,
        400
      );
      var vectorCursor = table.Find(
        filter3,
        new TableFindOptions<Book>()
        {
          Sort = Builders<Book>.TableSort.Vector(
            b => b.SummaryGenresVector,
            new float[]
            {
              0.016326904f,
              -0.031677246f,
              0.04815674f,
              0.0033435822f,
              0.01876831f,
            }
          ),
          Projection = Builders<Book>
            .Projection.Include(b => b.Title)
            .Include(b => b.Author),
          Limit = 3,
        }
      );
      foreach (var document in vectorCursor)
      {
        Console.WriteLine($"{document.Title} by {document.Author}");
      }
    }
  }
}
1 This is the ConnectToDatabase function from the previous section.
2 This code expects that you have a table named quickstart_table in a keyspace named quickstart_keyspace. If you used a different keyspace or table name in the previous sections, update it here.

Next steps

For more practice, you can continue building with the table that you created here. For example, try inserting more data to the table, or try different searches. The Data API reference provides code examples for various operations.

Insert data from different sources

This quickstart demonstrated how to insert structured data from a JSON file into a table, but you can insert data from many sources.

Tables use fixed schemas. If your data is unstructured or if you want a flexible schema, you can use a collection instead of a table. See the quickstart for collections.

Perform more complex searches

This quickstart demonstrated how to find data using filters and vector search. To learn more about the searches you can perform, see Find rows (C#), Filter operators for tables (C#), Sort clauses for tables (C#), and Find data with vector search.

Was this helpful?

Give Feedback

How can we improve the documentation?

© Copyright IBM Corporation 2026 | Privacy policy | Terms of use Manage Privacy Choices

Apache, Apache Cassandra, Cassandra, Apache Tomcat, Tomcat, Apache Lucene, Apache Solr, Apache Hadoop, Hadoop, Apache Pulsar, Pulsar, Apache Spark, Spark, Apache TinkerPop, TinkerPop, Apache Kafka and Kafka are either registered trademarks or trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries. Kubernetes is the registered trademark of the Linux Foundation.

General Inquiries: Contact IBM