Well, I’ve switched databases again. After briefly trying NHibernate, then switching to RavenDB, then looking at Karvonite, I think I’ve found what I was looking for in Sterling. I was looking for an easy way to persist objects. NHibernate is nice, but compared to object-oriented databases, it’s a lot of work (database schema’s, mapping files, etc.). RavenDB introducted me to the NoSql alternatives, but has a high licensing fee and is a little to heavy for my needs. Karvonite was actually what I was looking for, but Sterling will be more actively under development and supported. There’s little news on the Karvonite site.
So, I’m developing a WPF desktop application, and want to work with Sterling. This is possible since 1.4 beta (although I had to sign the assemblies myself for now).
First, I will add my references to Wintellect.Sterling.Server and Wintellect.Sterling.Server.FileSystem. Next, I create my DatabaseInstance:
public class SterlingDatabaseInstance : BaseDatabaseInstance { protected override List<ITableDefinition> RegisterTables() { return new List<ITableDefinition> { CreateTableDefinition<Patient, Guid>(x => x.Id), CreateTableDefinition<JournalEntry, Guid>(x => x.Id) .WithIndex<JournalEntry, DateTime, Guid>(JournalEntryEntryDateIndex, x => x.EntryDate) }; } public override string Name { get { return "SterlingDatabaseInstance"; } } }
Next, we need the Sterling engine. As per the documentation, “The Sterling engine should always be activated at the beginning of the application, and disposed of at the end. It should live as long as the application does.” I will do this in my App.xaml.cs. I could choose to instantiate a new SterlingEngine the first time a repository is used. But I would need to dispose it when my application shuts down, so I need code in App.xaml.cs anyway.
As I will be needing the database in my repositories, I’m making a DatabaseService class:
public static class DatabaseService { private static SterlingEngine _engine; private static ISterlingDatabaseInstance _databaseInstance; public static void Start() { _engine = new SterlingEngine(); _engine.Activate(); var folder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "MyApp/"; var driver = new FileSystemDriver(folder); _databaseInstance = _engine.SterlingDatabase.RegisterDatabase<SterlingDatabaseInstance>(driver); } public static ISterlingDatabaseInstance Current { get { return _databaseInstance; } } public static void Stop() { _engine.Dispose(); } }
Now, in my App.xaml.cs, on starting my application, I just call DatabaseService.Start(). And on exiting the application, I call DatabaseService.Stop().
Then, finally, I can implement my repository. Because I’m using a BaseRepository<T>, where T is any aggregate root, this was fairly simple:
public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity, new() { public IList<T> GetAll() { var query = (from key in DatabaseService.Current.Query<T, int>() select key.LazyValue.Value).ToList(); return query; } public void Save(T aggregate) { DatabaseService.Current.Save(aggregate); } public void Delete(T aggregate) { DatabaseService.Current.Delete(aggregate); } }
Notice the fact that T must have a parameterless constructor. The key variable will have a property Key, which is the primary key of your table, and a LazyValue, which is the actual object. This isn’t loaded until you call it, and the same goes for Indexes, which gives you a preformance advantage. But more on that later (maybe).