We are excited to be a part of AWS re:Invent 2024. Visit us at booth #1844 in Las Vegas.More info
Blog

Using auto-values in Aerospike LINQPad driver

profile-headshot
Richard Andersen
Principal Engineer
February 8, 2024|7 min read

When working with NoSQL databases like Aerospike, which are designed for unstructured data storage, adopting strongly typed languages like C# may introduce programming complexities. These can stem from verifying the presence of "bins" (akin to columns) within a record and bin data types that can change between records.

Auto-Values (AValue is the class) simplify the need to check, cast, or convert values between Aerospike data types and .NET data types. They provide a rich set of operations and seamlessly work with any type of data, including collections and JSON. They provide protection against null reference exceptions, invalid cast exceptions, conversion exceptions, etc. To explore the LINQPad or the Aerospike LINQPad driver in more detail, kindly click on the respective links provided.

Example set

The following illustrates an Aerospike set where different records have a varied number of bins, and bins in the record set can have varying data types (e.g., bin BinA can be a double, long, string, or list in different records).

Using Auto-Values in Aerospike LINQPad Driver-demo-types-display 1707410345724

Display of the DemoTypes set

Note that the LINQPad connection tree (left side) is expanded, illustrating the bins for the set DemoTypes. Under the set name, each bin is listed, displaying its associated data type. Take note of the symbols after the data type. A * indicates this bin has different data types between records. A ? indicates this bin wasn’t present in some of the records within this set. These symbols provide a quick view of the set and expected values. In the Results pane (bottom-right), bins with null are not present in that record.

Simple cast examples

Below are examples that illustrate the difference between using Aerospike data types, C# data types, and Auto-Values. Let’s begin with an example where Auto-Values are not used:

Using Auto-Values in Aerospike LINQPad Driver-data-type-casting 1707410345018

Shows that casting to the proper data type is required

Notice that there are no results from the query, even though it should have matched one record. The reason it failed is because “456” is an Int32, and the DB numeric values are Int64. So, “456” needs to be cast to Int64 (long). Also, we need to check to make sure the bin is present in all records; otherwise, a null exception is thrown.

Below is an example showing these changes:

Using Auto-Values LINQPad Driver-updated-query-using-required-cast 1707410344508

Updated query using required cast

Let’s look at the same query using Auto-Values:

Using Auto-Values in Aerospike LINQPad Driver-no-required-testing-or-casting 1707410346940

Using Auto-Values doesn’t require testing or casting

In the given example, you do not have to verify the existence of the bin or explicitly cast "456" to a long data type. Auto-Values take care of not only casting but also converting. Conversion between any of the .NET primitive types to or from any Aerospike data types is seamless. It also handles nullable values, JSON objects, and collection data types (CDT).

Auto-Values support all standard operations like ==, >, <, etc. They also support all the equality and comparison operations.

Below are some additional examples:

Using Auto-Values in Aerospike LINQPad Driver-updated-query-using-required-cast-queries-with-different-auto-value-uses 1707410347730

Queries above show different uses of Auto-Values

Handling unsupported data types

Aerospike supports a limited set of data types. They include:

  • String

  • Integer (Int64)

  • Double

  • Boolean

  • Blob/Bytes (byte[])

  • List

  • Map (Directory)

  • Geospatial (GeoJSON.NET)

The driver has extended support by allowing the following .NET data types:

  • DateTime, DateTimeOffset, TimeSpan: These values are mapped to either an Aerospike string or long data types depending on the connection or API configuration. Auto-Values will automatically take care of these conversions to or from the database.

  • JSON: These values are mapped to an Aerospike Map data type where the JSON property name is the key in the Map, and the JSON value is the Map value. JSON arrays are mapped to Aerospike “List.” Nested JSON structures are completely supported, and the driver takes care of all conversions to or from the database.

Below are examples where .NET DateTimeOffset, DateTime, and TimeSpan instances are used to obtain matching records. The values stored in the Aerospike database are either strings or an Int64 value (number of nanoseconds from Unix Epoch). The driver will manage the conversion between these different types.

Using Auto-Values in Aerospike LINQPad Driver-datetime-datetimeoffset-timespan 1707410345257

Queries using .NET DateTime, DateTimeOffset, and Timespan

By the way, you can control how values are converted and displayed through the properties located in the "Display/Conversion Options" section of the connection dialog.

Conversion

Auto-Values provide a rich set of conversion functions, including:

  • Convert<T> - Will try to convert to the provided .NET data type. If it cannot, an invalid cast exception is thrown.

  • Is{data type} – Use to test if the underlying .NET data type is that {date type}. Examples of these functions are: IsList, IsCDT, IsJSON, IsInt16, IsNumeric, IsString, etc.

  • To{data type} – Will try to convert to the .NET {data type}, if possible. Note {data type} can be Dictionary, List, .NET native type, etc. Examples of these functions are: ToList, ToBoolean, ToByte, etc.

  • TryGetValue<T> – This will try to match a provided value and convert the value into the provided .NET data type. If not successful, the default value of that data type and/or false is returned, depending on usage. This function can be applied against CDTs or non-CDT values.

  • TryGetValue – This will try to match the provided value. If successful, the matched value is returned as an Auto-Value. If not, an empty Auto-Value, false, or null can be returned depending on usage. This function can be applied against CDTs or non-CDT values.

  • AsEnumerable – This will convert an Auto-Value into an enumerable object if it is a database CDT. If not a CDT, an empty enumeration is returned. All elements in the CDT are scanned and converted into Auto-Values. This will provide the highest level of protection against invalid casts or null value reference exceptions. This also allows for using the advanced Auto-Value functions outlined in the Collection Data Types section.

  • Implicit Casting – Auto-Values know how to implicitly cast from an Aerospike data type to any .NET primary type without explicitly providing the type. Detailed documentation can be found through IntelliSense or by reviewing the function’s respective documentation.

Collection data types

Auto-Values can seamlessly be used to find elements within CDTs. These functions are based on standard C# methods. Examples of these operations are:

  • Contains – Returns true if the matching value is contained in a bin’s value or an element within a CDT. The matching options determine how the matches occur.

  • FindAll – Returns a collection of matching Auto-Values. A match can occur as a bin’s value or an element within a CDT. The matching options determine how the matches occur. If no matches are found, an empty enumerable is returned.

  • TryGetValue – Returns the first matching value (as an Auto-Value) contained in a bin’s value or an element within a CDT. If the Auto-Value is not found, an Empty Auto-Value is returned.

  • OfType<T> - Tries to cast the Auto-Value to the provided .NET type, creating a new collection of those types. If a value cannot be cast, it will be ignored.

  • Cast<T> -- Will cast the Auto-Value to the provided .NET type. If it cannot be cast, an invalid cast exception will occur.

  • Convert<T> - Will try to convert the Auto-Value, resulting in a collection of converted .NET values. If an Auto-Value cannot be converted, it will be ignored.

Below are some examples using “Contains” and “FindAll” methods:

Using Auto-Values in Aerospike LINQPad Driver-queries-using-contains-and-findall-methods- 1707410347068

Queries using the Contains and FindAll methods

You can find additional examples in the LINQPad sample folder. Below is an example of “drilling” into several different sub-collections using LINQ. This example finds all invoices for a certain song track, resulting in a collection of customers. This example is located in the CDT-Json-Docs sample LINQPad script.

Using Auto-Values in Aerospike LINQPad Driver-linq-query 1707410346440

LINQ Query

Primary key

Auto-Values also extend to primary keys. They have the same features as found in the Bin Auto-Values. There are a few additional features, such as digest values. If the primary key value is not saved (only the digest is used), matching to a value can still occur using Auto-Values. Below is an example where the digest is only available; note that the actual value must be used.

Using Auto-Values in Aerospike LINQPad Driver-string-value-database-ingest 1707410347582

Query using a string value by means of the database digest

LINQPad driver samples

You can find samples for the Aerospike LINQPad driver in the samples folder or under the “Samples” tab in LINQPad.