RavenDB: storing data
We have seen how to “install” RavenDB and how to read data, well…one way to read data: there are lot of options we’ll dive in the near future. Now it’s time to see how to store data in the database, what are the basic concepts behind RavenDB storage engine and some “tricks” to achieve all what you want.
Let’s do something interesting…
var personId = "";
using( var session = store.OpenSession() )
{
var person = Person.CreateNew( "Mauro", "Servienti" );
session.Store( person );
session.SaveChanges();
personId = session.Advanced.GetDocumentId( person );
}
We create a new Person (we’ll see in a minute Person class peculiarities) and simply store it in the database, trivial. We also do one interesting thing we ask to the database to get back the stored person identifier.if we take a look at the data we find something like the following:
Figure: RavenDB data displaying 2 documents.
Where the “green” document is the person recently saved and the “blue” one the system document that keeps track of the generated identifiers…the name of the document (Hilo) should be familiar to NHibernate developers.
The key point here is that we have not assigned an identifier to the Person instance, but the database did it for us. This is due to a set of conventions that drives some of the RavenDB behavior, the Person class is defined in the following manner:
public class Person
{
public static Person CreateNew( String firstName, String lastName )
{
return new Person()
{
FirstName = firstName,
LastName = lastName
};
}
[JsonConstructor]
private Person()
{
}
public String Id { get; private set; }
public String FirstName { get; private set; }
public String LastName { get; private set; }
}
There are lots of things to notice:- The class has e read-only “Id” property, the convention is: if the class has a property named Id consider it to be the document identifier (the primary key), if it is null, string empty or a string that ends with “/” append a new identifier;
- The class has a private default constructor decorated with the JsonConstructor attribute whose role is to tell to the json serializer which is the constructor to use to deserialize the document (it is required only if there are no parameter-less constructors);
- Have I told that everything is stored in the database as a document in the database?
- In future posts we’ll see why I have decided to expose FirstName and LastName property both as read-only, currently trust me…it just works;
using( var session = store.OpenSession() )
{
var person = session.Load<Person>( personId );
}
Here we can observe another way of loading data, the Load<T> method: the load method expects an identifier (or a set of identifiers) and goes directly to the database, bypassing the indexing engine, and loads the requested document(s), if a document cannot be found null is returned to the caller.The keywords are: bypassing the indexing engine (indexing is covered in the next post).
Document Shape
Keep in mind that the database is very flexible and does not impose any requirement on the data shape and design, as we have seen we can use attributes to “drive” the json serializer toward its goal. We’ll discover that document databases suggest a preferred shape for data, shape that can you drive to success.
.m