Using auto-values in Aerospike LINQPad driver
Tags: dotnet, linq, csharp
Published: 2024-02-08 20:03:53


![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/using-auto-values-in-aerospike-linqpad-driver-blog_1707410347927.webp)

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](https://www.linqpad.net) or the [Aerospike LINQPad driver](https://aerospike.com/developer/blog/aerospike-for-linqpad) 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).

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-demo-types-display_1707410345724.png)
_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:

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-data-type-casting_1707410345018.png)
_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:

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20%20LINQPad%20Driver-updated-query-using-required-cast_1707410344508.png)
_Updated query using required cast_

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

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-no-required-testing-or-casting_1707410346940.png)  
_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)](https://aerospike.com/developer/tutorials/cdt).

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

Below are some additional examples:

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-updated-query-using-required-cast-queries-with-different-auto-value-uses_1707410347730.png)
![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-different-auto-value-uses_1707410346197.png)
_Queries above show different uses of Auto-Values_

## Handling unsupported data types

Aerospike supports a limited set of [data types](https://aerospike.com/docs/server/guide/data-types/scalar-data-types). They include:
- String
- Integer (Int64)
- Double
- Boolean
- Blob/Bytes (byte[])
- List
- Map (Directory)
- Geospatial ([GeoJSON.NET](https://github.com/GeoJSON-Net/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](https://aerospike.com/docs/server/guide/data-types/cdt-map) 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.

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-datetime-datetimeoffset-timespan_1707410345257.png)
_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:

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-queries-using-contains-and-findall-methods-_1707410347068.png)
_Queries using the Contains and FindAll methods_

You can find additional examples in the [LINQPad sample folder](https://github.com/aerospike-community/aerospike-linqpad-driver/tree/main/linqpad-samples/Cloud).
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](https://github.com/aerospike-community/aerospike-linqpad-driver/blob/main/linqpad-samples/Native/CDT-Json-Docs.linq) sample LINQPad script.

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-linq-query_1707410346440.png)
_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.

![](https://developer-hub.s3.us-west-1.amazonaws.com/richard-andersen/Using%20Auto-Values%20in%20Aerospike%20LINQPad%20Driver-string-value-database-ingest_1707410347582.png)
_Query using a string value by means of the database digest_

## LINQPad driver samples

You can find samples for the [Aerospike LINQPad driver](https://github.com/aerospike-community/aerospike-linqpad-driver) in the [samples folder](https://github.com/aerospike-community/aerospike-linqpad-driver/tree/main/linqpad-samples/Cloud) or under the “Samples” tab in [LINQPad](https://www.linqpad.net/nugetsamples.aspx).