RizeDb 2.0.0
dotnet add package RizeDb --version 2.0.0
NuGet\Install-Package RizeDb -Version 2.0.0
<PackageReference Include="RizeDb" Version="2.0.0" />
paket add RizeDb --version 2.0.0
#r "nuget: RizeDb, 2.0.0"
// Install RizeDb as a Cake Addin #addin nuget:?package=RizeDb&version=2.0.0 // Install RizeDb as a Cake Tool #tool nuget:?package=RizeDb&version=2.0.0
Document-Oriented
RizeDb has a document-oriented implementation that allows for the storing, indexing and retrieving of documents. Documents are not stored into tables and have very little structure to them.
RizeDb's document store requires no schema and document values can change types without requiring the database to update all existing data. By default, nearly all document data is indexed so that finding data is fast and easy.
Table of Contents
RizeDb Primer
The first step to creating a document store is simply to instantiate the DocumentStore object with a stream.
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
//Code goes here
}
}
Once your document store is created, create POCO classes.
public class Order
{
public long Id { get; set; } //This is the only required field
public string Number { get; set; }
public DateTime Date { get; set; }
public List<OrderItem> OrderItems = { get; set; }
}
public class OrderItems
{
public string ItemName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
Now that your POCO classes are created, instantiate and fill an Order object with data.
var order = new Order()
{
Numer = "1001",
Date = DateTime.Now,
OrderItems = new List<OrderItem>();
}
order.OrderItems.Add(new OrderItem()
{
ItemName = "Sun Glasses",
Price = 19.99,
Quantity = 1
});
order.OrderItems.Add(new OrderItem()
{
ItemName = "Flashlight",
Price = 10.50,
Quantity = 4
});
Once your order is ready to be stored simply add it to a document collection.
documentStore.Store("Orders", order);
This will store the order object and its' items as one document into a collection named "Orders". If the collection "Orders" does not already exist it will be created. Now that the order document has been stored into a collection it will have a unique value assigned to the Id property of order. This The Id value is what will be used to retrieve, update or delete the order in the future.
Retrieving your document is as simple as requesting it by Id.
var order = documentStore.Retrieve<order>("Orders", 1 /*Assuming the document Id is 1*/);
The retrieve method will create an Order object and its' OrderItem objects and populate them with the exact same data that was stored.
You can also lookup documents by values.
var orders = documentStore.Retrieve<order>("Orders", o => o.Number == "1001");
This call to the Retrieve method will create an IEnumerable object containing all Orders objects with the Number "1001".
You can also search by child object values.
var orders = documentStore.Retrieve<order>("Orders", o => o.OrderItems.Any(i => i.ItemName == "Flashlight"/);
Again you will get an IEnumerable object containing all orders that have an order item with the ItemName of "Flashlight".
You can even use a different object to retrieve data.
public class OrderHeader
{
public long Id { get; set; }
public string Number { get; set; }
}
var orderHeader = documentStore.Retrieve<OrderHeader>("Orders", 1 /*Assuming the document Id is 1*/);
This call will create and return an OrderHeader object with the Number property set to "1001".
And finally you can change the type of the property and the values will still get set as long as they are compatible.
public class OrderHeader2
{
public long Id { get; set; }
public int Number { get; set; } //<-- This was changed to an Int32
}
var orderHeader2 = documentStore.Retrieve<OrderHeader2>("Orders", 1 /*Assuming the document Id is 1*/);
Now the newly create OrderHeader2 will have an integer value for the Number property set to 1001. Changing types will work for most types, but some are not compatible and will either be null or default when the document is retrieved.
Operations
Storing
One of the many downsides of Relational Databases is the work it takes to create and alter tables. And while Relation Databases provide many benefits, often developers don't need those benefits and so the extra work becomes a barrier to the rest of the development process. The Document Store in RizeDb was designed to make storing, retrieving, updating and deleting of records as easy as possible. In fact, there is only one requirement and that is that every document has a property named Id that is along. The Id field is the primary key and is required to be present when adding, updating or removing a document.
As seen in the [Getting Started] section adding a document is as easy as:
class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
var customer = new Customer() { Name = "John Smith" }
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
documentStore.Store("Customers", customer);
}
}
In the above code example, the customer was stored in the document store and a unique int64 value was assigned to the Id property. It is important to note that if the Id property is not 0 when storing a document that RizeDb will first try and find an existing document with that Id and replace it with the new document. If a document did not already exist, the new document will be added without generating a new Id value.
Retrieving
The exception to the rule is Byte arrays. So searching and retrieving documents is very easy and flexible.
The simplest way to retrieve a document is with the Id.
class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
var customer = documentStore.Retrieve<Customer>("Customers", 1);
}
}
The code above will look for the document with the Id of one and if found will create a customer object and populate any matching field names with the stored data. Using the Id will return just one document if a document is found.
A lambda predicate can also be used to retrieve documents.
class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
var customers = documentStore.Retrieve<Customer>("Customers", c => c.Name == "John Smith");
}
}
The code above will look for any Document in the Customers collection that has a Name field with the value "John Smith". Since the system cannot be sure that only one document matches the predicate an IEnumerable of Customer is returned. With all matching documents. There are some scenarios where properties cannot be searched on, or where they may not find matching documents even though they exist. These scenarios are always a result of index changes. Please see Index Optimizing for more details.
Updating
Updates are essentially overwriting the existing document. If you create a new document and assign it an Id that already exists in the collection. The previous document will be removed and the new document will be added. This means that all existing data will be lost unless it is included in the new document.
In the following example, the current customer will be loaded and the name changed.
class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
var customer = documentStore.Retrieve<Customer>("Customers", 1);
customer.Name = "John Doe";
documentStore.Store("Customers", customer);
}
}
Removing
Removing a document is very straight forward. All you need is the Id of the document.
using(var stream = new MemoryStream())
{
using(var documentStore = new RizeDb.DocumentStore(stream))
{
var customer = documentStore.Remove("Customers", 1);
}
}
The document with the Id of 1 will no longer exist in the customers collection.
Transaction Group Operations
The Transaction Group ensures that all operations in that group are written to the document store or none of them are. An example of this would be if you create a new customer and that customer has a new order. You would not want the customer being stored in a collection without the order or the Order without the Customer.
When using a transaction group if there is some sort of failure and the order or customer is not fully committed to the document store. Both operations will be rolled back as if they never happened.
The following example shows how easy it is to use a Transaction Group.
var transactionGroup = documentStore.CreateTransactionGroup()
.Store("Customer", customer)
.Store("Order", order)
.Commit();
Additionally, you can have an action that gets called after each operation. This allows you to provide information such as the Id of parent documents to children documents.
var transactionGroup = documentStore.CreateTransactionGroup()
.Store("Customer", customer, c => order.CustomerId = c.Id)
.Store("Order", order)
.Commit();
It is important to remember to call the Commit method without it your documents will not be stored.
Indexing
When a collection is created an index is added to the Id field. Additional indexes can be created on properties so that look ups on those properties can be much faster.
class Log
{
public long Id { get; set; }
[Index(IndexSearchOptions.Dates)]
public DateTime Date { get; set; }
[Index(IndexSearchOptions.String)]
public string Source { get; set; }
public string Message { get; set; }
}
In the above example, all properties will be indexed except for the Message property. Since string properties are slow to index especially when they are large, not adding indexing to the Message property is a good idea.
Since this is a document database, property types can be changed. If you change the property type on an indexed property, you may want to tell the database that it needs to search the old index as well as the new one. In the example below the Source field was changed to an Int and the additional index attribute was added to let the engine know that it needs to search the string index as well.
class Log
{
public long Id { get; set; }
[Index(IndexSearchOptions.Dates)]
public DateTime Date { get; set; }
[Index(IndexSearchOptions.String)]
[Index(IndexSearchOptions.Int)]
public int Source { get; set; }
public string Message { get; set; }
}
var customers = documentStore.Retrieve<Log>("Logs", c => c.Source = "23");
Both the String index, and Int index will be searched when retrieving documents using that field.
As a side note, when searching through multiple indexes for values threading is used. This helps keep searching fast but optimizing your indexes can still have significant benefits to the performance of the system.
Dropping Collections
There may come a time where you no longer need the data in a collection. You can drop that collection and all of its' indexes. When a collection is dropped its' file space is flagged for reuse. This allows other collections and or new collections to use that file space in the future.
To drop a collection follow the example below.
database.DropCollection("Logs");
Encryption
RizeDb supports AES encryption. When a database is encrypted all data including the logs are encrypted so that no part of your database is exposed. However, of the password that unlocks the database is ever lost, you will not be able to recover your data. To use encryption the database must be created with it, and once created the password cannot be changed or removed.
Future versions of RizeDb will allow for changing and removing of passwords but for now, it is a one-way trip.
An example of creating an encrypted data store can be seen below.
using (var database = new RizeDb.DocumentStore(stream, "Password"))
{
//Do operations here
}
Use the same code when opening the database in the future.
Settings
Every application needs some sort of location to store simple data. Perhaps login credentials to a third-party app. Maybe a version number of your app or a timestamp of the last time data was synchronized. Whatever it is, it does not make sense to create a custom file or a full collection in the database to store that data. The Document Store in RizeDb has a feature called Settings. The feature allows you to store whatever objects you want with a key-value pair interface. And if you are using encryption the data stored in settings will be encrypted as well.
Using Settings is simple.
using (var database = new RizeDb.DocumentStore(stream)) {
var settings = new SettingsClass() { Value = "Hey Yall" };
database.SetSetting("MySetting", settings);
}
To retrieve a setting is simple.
using (var database = new RizeDb.DocumentStore(stream))
{
var restoredSetting = database.GetSetting<SettingsClass>("MySetting");
}
vizeotech@outlook.com
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.5.5)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
-
net5.0
- System.Memory (>= 4.5.5)
-
net6.0
- System.Memory (>= 4.5.5)
-
net7.0
- System.Memory (>= 4.5.5)
-
net8.0
- System.Memory (>= 4.5.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on RizeDb:
Package | Downloads |
---|---|
EnvironmentVault2.Shared
Supporting assembly for Environment Vault. |
|
EnvironmentVault.Shared
Companion assemblies for Environment Vault |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.0.0 | 108 | 8/28/2024 |
2.0.0-beta5 | 113 | 8/11/2023 |
2.0.0-beta4 | 119 | 1/23/2023 |
2.0.0-beta3 | 181 | 9/18/2022 |
2.0.0-beta2 | 182 | 9/18/2022 |
2.0.0-beta | 141 | 9/6/2022 |
1.6.5 | 517 | 7/20/2021 |
1.6.0 | 355 | 5/16/2021 |
1.5.0 | 503 | 4/11/2021 |
1.4.0 | 495 | 4/8/2021 |
1.3.5 | 334 | 3/21/2021 |
1.3.0 | 647 | 9/16/2020 |
1.2.0 | 414 | 9/10/2020 |
1.1.0 | 497 | 8/19/2020 |
1.0.2 | 469 | 7/9/2020 |
1.0.1 | 574 | 7/26/2019 |
1.0.0 | 657 | 7/24/2019 |