Core concepts of indexing in SisoDb – Screencast

Time for episode number three. In this 8 minute episode, I’ll give you some short information about the concept of “Indexing” in SisoDb. I’ll show you how to use the Glimpse plugin to inspect information about structure schemas.

//Daniel

IoC with SisoDb in ASP.Net MVC

I just put together a short screencast (about 4min) showing you have to configure SisoDb with an IoC-container in ASP.Net MVC using “One session per HttpRequest”. For this demo I will use Ninject.

The screencast is hosted in the SisoDb channel at Vimeo.

Updated: Mike Paterson has a GitHub repository with code for the episode, found here: https://github.com/devlife/Sandbox/tree/master/SisoDb

Summarized

After having installed the “Ninject.MVC3 NuGet package”, I added a NinjectModule named “DbConfig” under a new folder/namespace “IoCConfig”.

public class DbConfig : NinjectModule
{
    public override void Load()
    {
        var db = "CoreConcepts".CreateSql2012Db();
        Kernel.Bind<ISisoDatabase>()
            .ToMethod(ctx => db)
            .InSingletonScope();

        db.CreateIfNotExists();

        Kernel.Bind<ISession>()
            .ToMethod(ctx => db.BeginSession())
            .InRequestScope();
    }
}

After that we just need to ensure the module is loaded by Ninject in the bootstraper, which is installed by the Ninject.MVC3 NuGet, under “App_Start”. The only change that is needed is adding one row to the “CreateKernel” member, so that it look like this:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    //ADD THIS TO LOAD OUR MODULE(s)
    kernel.Load(typeof(MvcApplication).Assembly);

    RegisterServices(kernel);
    return kernel;
}

We are now all set and can take a dependency on “ISession” in our controllers. Either in the constructor or by resolving it using a static class/method/service locator concept against the Ninject IoC-container. Since my sample uses Db-access in each action, I used constructor injection.

public class CustomerController : Controller
{
    private readonly ISession _dbSession;

    public CustomerController(ISession dbSession)
    {
        _dbSession = dbSession;
    }

    //...
}

That’s it.

//Daniel

Vimeo channel with screencasts of SisoDb

Just created a channel on Vimeo, for screencasts about SisoDb. The first contribution is a short (8 minutes) Getting started episode.

Updated: Mike Paterson has a GitHub repository with code for the episode, found here: https://github.com/devlife/Sandbox/tree/master/SisoDb

I’ll keep filling this channel with short screencasts, hopefully never longer than 10minutes.

//Daniel

SisoDb v11.4.0 – with new named queries

So, the versions of SisoDb keeps pumping out and in this post I will cover a new feature introduced in v11.4.0. You can always have a look at the release notes to get full details of what has changed.

Refactoring friendly Named Queries

A named query in SisoDb is the invocation of a stored procedure returning JSON. As of v11.4.0 you can let SisoDb generate them as well as invoke them using lambda expressions. Lets have a look.

Normal Query
This is a basic query not using stored procedures. It can be consumed in two variations, via Session or via UseOnceTo.

using (var session = database.BeginSession())
{
    return session.Query<Customer>().Where(c => 
            c.CustomerNo >= customerNoFrom 
            && c.CustomerNo <= customerNoTo 
            && c.DeliveryAddress.Street == "The delivery street #544").ToArray();
}
return database.UseOnceTo().Query<Customer>().Where(c => 
        c.CustomerNo >= customerNoFrom 
        && c.CustomerNo <= customerNoTo 
        && c.DeliveryAddress.Street == "The delivery street #544").ToArray();

Named Query
A named query is represented by the INamedQuery interface. It’s very slim, and there’s one default implemantation of it, namely “NamedQuery”.

public interface INamedQuery
{
    string Name { get; }
    IEnumerable<IDacParameter> Parameters { get; }
    void Add(params IDacParameter[] parameters);
}

Consuming them means magic strings representing e.g properties of your models. This could of course be avoided if you implement/inherit any of these types and create a typed named query. But then you have a query that is detached from your model but implicitly dependent on any changes in it. Is there a better way? Sure!

Nicer Named Queries
First, we will let SisoDb create the stored procedure for us, using our model and lambda expressions.

using (var session = database.BeginSession())
{
    session.Advanced.UpsertNamedQuery<Customer>("CustomersViaSP", builder => 
        builder.Where(c =>
            c.CustomerNo >= customerNoFrom
            && c.CustomerNo <= customerNoTo
            && c.DeliveryAddress.Street == "The delivery street #544"));
}

This little snippet will create the stored procedure for us in the database. If the stored procedure exists, it will be overwritten. Now, lets consume it, and again using our model and lambda expressions:

using (var session = database.BeginSession())
{
    return session.Advanced.NamedQuery<Customer>("CustomersViaSP", c => 
        c.CustomerNo >= customerNoFrom
        && c.CustomerNo <= customerNoTo
        && c.DeliveryAddress.Street == "The delivery street #544").ToArray();
}

Does this have any impact on the performance of the query? Yes! The case below contains a rather small set of Customers. Only 5000 (read more about performance here) First, there’s two rows representing the manual query. Then there’s two rows representing the stored procedure. The first row in each pair takes a penalty hit, cause it’s the first time it’s executed. This is why your application should hold ONE LONG LIVED INSTANCE OF the ISisoDatabase.

The result: 0.0025s vs 0.0006s

That’s all about the new Named queries.

If any of the links above doesn’t work. The documentation is duplicated on GitHub.

//Daniel

Some XSockets and SisoDb fun – Part 2 of 2

This is a continuation of Some XSockets and SisoDb fun – Part 1 of 2 which more was about getting started with XSockets.Net. This post is about putting SisoDb to use. The steps we will go through are:

Get the Code

The code is located at GitHub. Both the SisoDbClient.Js and a sample app matching the sample we will create here.

  • Step 1 – Create a model
  • Step 2 – Inserts – Add support to the socket handler
  • Step 3 – Inserts – Hook up the UI
  • Step 4 – GetById – Add support to the socket handler
  • Step 5 – GetById – Hook up the UI
  • Step 6 – Updates – Add support to the socket handler
  • Step 7 – Updates – Hook up the UI
  • Step 8 – Queries – Add support to the socket handler
  • Step 9 – Queries – Hook up the UI
  • Step 10 – DeleteById – Add support to the socket handler
  • Step 11 – DeleteById – Hook up the UI

Step 1 – Create a model

First of, we need a simple model to work with. Create a class library project named “Model” and add the following class:

public class Article
{
    public Guid ArticleId { get; set; }
    public int PLU { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Now, it’s time to extend our socket handler to support inserts of the newly created model.

Step 2 – Inserts – Add support to the socket handler

It’s time to start using SisoDb and we will now make the handler support inserts. But to do that we will need to setup some plumbing, which of course, also will be used for updates, deletes and queries. Now, lets install the “SisoDb core package” to the “XSocketHandler” project.

To support dynamic lambda expression when querying, we also need the “SisoDb.Dynamic” package so install that to.

Now, lets create the shell method accepting inserts. Add this to the “SisoDbHandler” class in the “XSocketHandler” project:

[HandlerEvent("Insert")]
public void Insert(InsertCommand command)
{
    //Use SisoDb, but resolve it via a configurable Runtime class.
}

Instead of locking down our handler to a specific provider of SisoDb, we will configure this in the application entry point instead, more precisely, in the “Server”. But before that, create a new class-library project named “Core”.

Now, install the “SisoDb core package” to this project as well.

The Core project will define a “Runtime” class that holds some resources that we will consume in our handler. This is a quick solution/hack and you would probably do it another way. Perhaps using MEF or some IoC-container framework. But lets keep it fairly simple. Add a new class called “Runtime” to the “Core project”.

public static class Runtime
{
    public static IResources Resources { get; set; }
}

We need to be able to resolve a ISisoDatabase and, given a type name, locate a certain structure/entity type. Lets define two simple Funcs for this.

public interface IResources
{
    Func<ISisoDatabase> DbResolver { get; set; }
    Func<string, Type> StructureTypeResolver{ get; set; } 
}

Lets initialize the Runtime. Install a specific SisoDb provider into your Server project. I will choose the Sql2012 provider.

To support dynamic lambda expression when querying, we also need the “SisoDb.Dynamic” package so install that to.

Add a class called “Resources” to the Server project and setup the two Func members that resolves a Db and Structure types. NOTE! The ISisoDatabase should be kept long lived since it contains caches of e.g Db-Schemas.

public class Resources : IResources
{
    private readonly ISisoDatabase _db;
    private readonly IDictionary<string, Type> _structureTypes;

    public Func<ISisoDatabase> DbResolver { get; set; }
    public Func<string, Type> StructureTypeResolver{ get; set; }

    public Resources()
    {
        //Func should resolve the SAME ISisoDatabase each time
        //Demo is the name of the connection string in App.Config
        _db = "Demo".CreateSql2012Db();
        _db.CreateIfNotExists();
        DbResolver = () => _db;

        //Simple key-value map for acceptable structure types
        _entityTypes = GetEntityTypes().ToDictionary(t => t.Name);
        StructureTypeResolver= name => _structureTypes[name];
    }

    private IEnumerable<Type> GetStructureTypes()
    {
        //This determines what Entities/Structures that will be accessible
        yield return typeof (Article);
    }
}

Now, assign an instance of the Resource class to the Runtime

static void Main(string[] args)
{
    Runtime.Resources = new Resources();
    //...
    //leave the rest untouched
    //...
}

Add a connection string to the App.Config in the Server project.

<connectionStrings>
  <add name="Demo" connectionString=
       "data source=.;initial catalog=Demo;integrated secuirty=true;"/>
</connectionStrings>

Now, lets fix the handler. I couldn’t get a constructor with arguments to work so we will resolve the Db inside it. Add a default constructor to the “SisoDbHandler” and resolve a Db to be used:

public class SisoDbHandler : XBaseSocket
{
    private readonly ISisoDatabase _db;

    public SisoDbHandler()
    {
        _db = Runtime.Resources.DbResolver();
    }

    //...
    //leave the rest untouched
    //...

Almost there. Fix the Insert method:

[HandlerEvent("Insert")]
public void Insert(InsertCommand command)
{
    var structureType = Runtime
        .Resources
        .StructureTypeResolver(command.StructureName);

    var result = new InsertResult
    {
        StructureName = command.StructureName,
        Json = _db.UseOnceTo().InsertJson(structureType, command.Json)
    };

    this.AsyncSend(result, "OnInserted");
}

The last steps that are missing is to create the “InsertCommand” and the “InsertResult”. Lets add them.

//Namespace: XSocketHandler.Commands
public class InsertCommand
{
    public string StructureName { get; set; }
    public string Json { get; set; }
}
//Namespace: XSocketHandler.Results
public class InsertResult
{
    public string StructureName { get; set; }
    public string Json { get; set; }
}

Our handler is now ready to serve insert calls. Lets consume it.

Step 3 – Inserts – Hook up the UI

The next step is to update our demo.html page and make it use the insert method. This is what we will start out from, with just a few minor adjustments from the previous post:

<!DOCTYPE html>
<html>
<head>
    <title>Demo - SisoDb-XSockets</title>
    <script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script src="Scripts/JXSockets-1.0.4.beta.js" type="text/javascript"></script>
    <script src="http://cloud.github.com/downloads/danielwertheim/
                 SisoDb-XSockets/sisodbclient-debug-v0.3.0.js" 
            type="text/javascript"></script>
        
    <script type="text/javascript">
        var my = {};

        $(function () {
            //Hook up client
            my.client = new SisoDbClient("ws://127.0.0.1:4502/SisoDbHandler");
            my.client.logger.enabled = true;
            my.client.connect();

            //Hookup UI to consume client
            $("#ping button").on("click", function () {
                my.client.ping($("#ping_message").val());
            });

            //Hookup listeners
            my.client.onPinged(function (data) {
                my.dumpResult("onPinged", data.Message);
            });

            //Some helpers
            my.dumpResult = function (action, result) {
                $("<li>").addClass(action)
                         .text(result)
                         .appendTo(".outputs ul:eq(1)");
            };
        });
    </script>
    <link href="Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <section class="inputs">
        <fieldset id="ping">
            <legend>Ping</legend>
            <label for="ping_message">Message</label>
            <input type="text" id="ping_message" placeholder="Message" />
            <button>Ping</button>
        </fieldset>
    </section>
    <section class="outputs">
        <ul>
            <li class="onPinged description">Ping result</li>
            <li class="onInserted description">Insert result</li>
            <li class="onDeletedById description">Delete by id result</li>
            <li class="onGetById description">Get by id result</li>
            <li class="onQuery description">Query result</li>
            <li class="onUpdated description">Update result</li>
        </ul>
        <ul></ul>
    </section>
</body>
</html>

First add a new Fieldset below the one for Ping.

<fieldset id="article_insert">
    <legend>Insert</legend>
    <div class="form-item">
        <label for="article_insert_name">Name</label>
        <input type="text" id="article_insert_name" placeholder="Name" />
    </div>
    <div class="form-item">
        <label for="article_insert_plu">PLU</label>
        <input type="text" id="article_insert_plu" placeholder="PLU" />
    </div>
    <div class="form-item">
        <label for="article_insert_price">Price</label>
        <input type="text" id="article_insert_price" placeholder="Price" />
    </div>
    <div class="form-actions">
        <button class="insert">Insert</button>
    </div>
</fieldset>

Now we need to make the UI invoke the socket handler when we click on Insert.

$(".inputs #article_insert .insert").on("click", function () {
    my.client.insert("Article", {
        Name: $("#article_insert_name").val(),
        PLU: $("#article_insert_plu").val(),
        Price: $("#article_insert_price").val()
    });
});

We also want to react on whenever an item is inserted, so lets hook that up:

my.client.onInserted(function (data) {
    my.dumpResult("onInserted", data.Json);
});

Now, fire up the Server and the MVC application and visit the demo.html page. Below I have tried the Ping operation and made a simple insert.

Step 4 – GetById – Add support to the socket handler

This time, most of the plumbing is already in place in the handler. Lets add GetById:

[HandlerEvent("GetById")]
public void GetById(GetByIdCommand command)
{
    var structureType = Runtime
        .Resources
        .StructureTypeResolver(command.StructureName);
    var structureSchema = GetStructureSchema(structureType);

    var id = ConvertId(command.Id, structureSchema);
    var result = new GetByIdResult
    {
        StructureName = command.StructureName,
        Id = command.Id,
        Json = _db.UseOnceTo().GetByIdAsJson(structureType, id)
     };

     this.AsyncSend(result, "OnGetById");
}

The above code needs two helper methods:

private IStructureSchema GetStructureSchema(Type structureType)
{
    return _db.StructureSchemas.GetSchema(structureType);
}

private static object ConvertId(string id, IStructureSchema structureSchema)
{
    return StructureId.Create(id, structureSchema.IdAccessor.IdType).Value;
}

Now, lets finish the GetById support in the handler. Add the GetByIdCommand and GetByIdResult.

//Namespace: XSocketHandler.Commands
public class GetByIdCommand
{
    public string StructureName { get; set; }
    public string Id { get; set; }
}
//Namespace: XSocketHandler.Results
public class GetByIdResult
{
    public string StructureName { get; set; }
    public string Id { get; set; }
    public string Json { get; set; }
}

Step 5 – GetById – Hook up the UI

Time to make the UI support the GetById operation. First add a new FieldSet that lets you enter an Id to return an item for.

<fieldset id="article_getById">
    <legend>Get by Id</legend>
    <div class="form-item">
        <label for="article_getById_id">Id</label>
        <input id="article_getById_id" type="text" placeholder="id"/>
    </div>
    <div class="form-actions">
        <button class="get">Get</button>
    </div>
</fieldset>

Make the UI invoke the handler:

$(".inputs #article_getById .get").on("click", function () {
    my.client.getById("Article", $("#article_getById_id").val());
});

Now, hook up the UI to react on the result of the GetByIdCommand.

my.client.onGetById(function (data) {
    my.dumpResult("onGetById", data.Json);
});

You should now be able to perform GetById operations, which will look like this:

Step 6 – Updates – Add support to the socket handler

Time to fix Updates. Add this to the handler:

[HandlerEvent("Update")]
public void Update(UpdateCommand command)
{
    var structureType = Runtime.Resources.StructureTypeResolver(command.StructureName);
    var structure = _db.Serializer.Deserialize(structureType, command.Json);
    var structureSchema = GetStructureSchema(structureType);

    _db.UseOnceTo().Update(structureType, structure);
            
    var result = new UpdateResult
    {
        StructureName = command.StructureName,
        Id = structureSchema.IdAccessor.GetValue(structure).Value.ToString()
    };

    this.AsyncSend(result, "OnUpdated");
}

Also add the UpdateCommand and the UpdateResult.

//Namespace: XSocketHandler.Commands
public class UpdateCommand
{
    public string StructureName { get; set; }
    public string Json { get; set; }
}
//Namespace: XSocketHandler.Results
public class UpdateResult
{
    public string StructureName { get; set; }
    public string Id { get; set; }
}

Step 7 – Updates – Hook up the UI

Time to make the UI support the Update operation. First add a new FieldSet that lets you enter an Id to load an item for. Then some controls that lets you update the values.

<fieldset id="article_update">
    <legend>Update - Load</legend>
    <div class="form-item">
        <label for="article_update_id">Id</label>
        <input id="article_update_id" type="text" placeholder="id"/>
    </div>
    <div class="form-actions">
        <button class="load">Load</button>
    </div>

    <legend>Update - Save</legend>
    <div class="form-item">
        <label for="article_update_name">Name</label>
        <input type="text" id="article_update_name" placeholder="Name" />
    </div>
    <div class="form-item">
        <label for="article_update_plu">PLU</label>
        <input type="text" id="article_update_plu" placeholder="PLU" />
    </div>
    <div class="form-item">
        <label for="article_update_price">Price</label>
        <input type="text" id="article_update_price" placeholder="Price" />
    </div>
    <div class="form-actions">
        <button class="update">Update</button>
    </div>
</fieldset>

Make the UI invoke the handler:

$(".inputs #article_update .load").on("click", function () {
    my.client.getById("Article", $("#article_update_id").val());
});

$(".inputs #article_update .update").on("click", function () {
    my.client.update("Article", {
        ArticleId: $("#article_update_id").val(),
        Name: $("#article_update_name").val(),
        PLU: $("#article_update_plu").val(),
        Price: $("#article_update_price").val()
    });
});

Now, extend the “onGetById callback”, since it now could represent either “GetById” or “Load”.

my.client.onGetById(function (data) {
    if ($("#article_update_id").val()) {
        var doc = JSON.parse(data.Json);
        $("#article_update_name").val(doc.Name);
        $("#article_update_plu").val(doc.PLU);
        $("#article_update_price").val(doc.Price);
    }
    else
        my.dumpResult("onGetById", data.Json);
});

Also hook up the “onUpdated callback”:

my.client.onUpdated(function (data) {
    my.dumpResult("onUpdated", data.Id.toString());
});

You should now be able to perform Update operations, which will look like this:

Step 8 – Queries – Add support to the socket handler

Time to fix Queries. Add this to the handler:

using SisoDb.Dynamic; //IMPORTANT! IMPORTANT! IMPORTANT!

[HandlerEvent("Query")]
public void Query(QueryCommand command)
{
    var structureType = Runtime
        .Resources
        .StructureTypeResolver(command.StructureName);
            
    var result = new QueryResult
    {
        StructureName = command.StructureName
    };

    using (var session = _db.BeginSession())
    {
        result.Json = session.Query(structureType).Where(command.Predicate).ToArrayOfJson();
    }

    this.AsyncSend(result, "OnQuery");
}

Also add the QueryCommand and the QueryResult.

//Namespace: XSocketHandler.Commands
public class QueryCommand
{
    public string StructureName { get; set; }
    public string Predicate { get; set; }
}
//Namespace: XSocketHandler.Results
public class QueryResult
{
    public string StructureName { get; set; }
    public string[] Json { get; set; }
}

Step 9 – Queries – Hook up the UI

Time to make the UI support Queries with lambda style syntax. First add a new FieldSet that lets you enter a query.

<fieldset id="article_query">
    <legend>Query</legend>
    <div class="form-item">
        <label for="article_query_predicate">Predicate</label>
        <input id="article_query_predicate" type="text" placeholder="predicate"/>
    </div>
    <div class="form-actions">
        <button class="query">Query</button>
    </div>
</fieldset>

Make the UI invoke the handler:

$(".inputs #article_query .query").on("click", function () {
    my.client.query("Article", $("#article_query_predicate").val());
});

Hook up the UI to display the query result for the “onQuery callback”.

my.client.onQuery(function (data) {
    $.each(data.Json, function (i, e) {
        my.dumpResult("onQuery", e);
    });
});

You should now be able to perform queries using syntax like "x => x.PLU >= 100"

Step 10 – DeleteById – Add support to the socket handler

Time to fix DeleteById. Add this to the handler:

[HandlerEvent("DeleteById")]
public void DeleteById(DeleteByIdCommand command)
{
    var structureType = Runtime
        .Resources
        .StructureTypeResolver(command.StructureName);
    var structureSchema = GetStructureSchema(structureType);

    var id = ConvertId(command.Id, structureSchema);

    _db.UseOnceTo().DeleteById(structureType, id);

    var result = new DeleteByIdResult
    {
        StructureName = command.StructureName,
        Id = command.Id
    };

    this.AsyncSend(result, "OnDeletedById");
}

Also add the DeleteByIdCommand and the DeleteByIdResult.

//Namespace: XSocketHandler.Commands
public class DeleteByIdCommand
{
    public string StructureName { get; set; }
    public string Id { get; set; }
}
//Namespace: XSocketHandler.Results
public class DeleteByIdResult
{
    public string StructureName { get; set; }
    public string Id { get; set; }
}

Step 11 – DeleteById – Hook up the UI

Again, lets just add some simple controls to allow you to enter an Id to delete.

<fieldset id="article_deleteById">
    <legend>Delete by Id</legend>
    <div class="form-item">
        <label for="article_deleteById_id">Id</label>
        <input id="article_deleteById_id" type="text" placeholder="id"/>
    </div>
    <div class="form-actions">
        <button class="delete">Delete</button>
    </div>
</fieldset>

Make the UI invoke the handler:

$(".inputs #article_deleteById .delete").on("click", function () {
    my.client.deleteById("Article", $("#article_deleteById_id").val());
});

Now, hook up the UI to react on the result of the GetByIdCommand.

my.client.onDeletedById(function (data) {
    my.dumpResult("onDeletedById", data.Id.toString());
});

You should now be able to perform DeleteById operations, which will look like this:

The SisoDbClient.Js

The client is using the XSockets.JsApi and is written using CoffeeScript. It’s not large, have a look at it on GitHub.

Where to go from here

The code is hosted on GitHub. Both the SisoDbClient.Js (which is authored using CoffeeScript) and the XSocketHandler. If this looks interesting, pull it down and extend the code yourself. E.g adding exception handling, but as of now, I have nothing more to cover in this post. Happy coding!

//Daniel

Some XSockets and SisoDb fun – Part 1 of 2

This is a two post series that will show you how to use XSockets and SisoDb to create a JavaScript client for SisoDb, that let’s you consume the db directly from JavaScript. Not saying it’s what you should do, just showing what you can do. In this first post we will look at getting started with XSockets and getting our custom handler in place. The next post will show the implementation. The steps in this post are:

  • Step 1 – Setup XSockets
  • Step 2 – Create the SisoDbHandler
  • Step 3 – Create a debuggable server
  • Step 4 – Implement a simple Ping method in our SisoDbHandler
  • Step 5 – Use the SisoDbClient.js to invoke our Ping member

Step 1 – Setup XSockets

First create a new empty ASP.Net MVC 3 project. Then install the NuGet package XSockets. Note! Use the Package Manager console

After the installation is done, some scaffolding templates (located under CodeTemplates) has been installed along with a XSocket-server and some web samples (located under XSockets). There’s also a new project “XSocketHandler” which is empty at the moment. This is where we will put our “SisoDbHandler“.

The development server will represent the server endpoint serving client connections. The client connection could come from e.g a JavaScript client using the XSockets.JsApi package or from .Net code using XSockets.External.

Now, lets start the development server via Windows explorer; and have a look at some of it’s commands. Start it and type: “help“.

The commands, currently available, are:

Try the “handlers” command. It will list the currently available handlers. And per default there’s one serving textual data (e.g JSON) and one serving binary data. And when we are done there will be a “SisoDbHandler“.

The included GenericText and GenericBinary handlers will let you, out of the box, be able to get up an running pushing JSON messages around and stream binary data. Hence you could e.g. create chats etc, right out of the box. Have a look at the included examples to see how easy it is.

Step 2 – Create the SisoDbHandler

A handler could be seen as a controller in ASP.Net MVC; and each handler serves one or many requests. To create a handler, turn back to the Package Manager Console and use the “scaffold” command and select “XSocketHandler“.

Name it: “SisoDbHandler“.

This will scaffold a new XSocketHandler named “SisoDbHandler” in the XSocketHandler project. Compile the solution and use “Show all files” in the MVC project, and you will see that the build events of the XSocketHandler project have copied the “XSocketHandler.dll” to the “XSocketServerPlugins” folder.

Now, start the server again and run the “handlers” command. You should now see the new “SisoDbHandler“.

Step 3 – Create a debuggable server

To be able to easily debug our handler and to manage deployment of dependencies during development, we will create a custom Server and not use the precompiled server under the MVC project.

Add a new console project. Name it “Server” and remove client profile for it (I wrote a quick post about how to get rid of it for-ever in about 5minutes.

Now, copy everything inside the folder “$MVCApp$\XSockets\DevelopmentServer” to “$Solution$\XSockets” and rename “XSocketServerPlugins” to “Plugins“. Clean it up so that it looks like this:

Add a reference to the “XSockets.Core.dll” above in the Server project.

Now, add an App.Config to the newly created Server-project. Copy the contents of “$MVCApp$\\XSockets\DevelopmentServer\XSockets.DevelopmentServer.Console.exe.config” to your newly created App.config file.

Locate the app-setting “XSocketServerPluginCatalog” and make it look like this:

<add key="XSocketServerPluginCatalog" value="..\..\..\XSockets\Plugins\" />

Go to the XSocketHandler project and open properties for it. Adjust the Pre- and Post- build events so that the dll gets copied to the Server-project instead.

Pre-build event

IF NOT EXIST "$(SolutionDir)XSockets\Plugins\" mkdir "$(SolutionDir)XSockets\Plugins\"

Post-build event

copy "$(TargetDir)$(TargetName).dll", "$(SolutionDir)XSockets\Plugins\"
copy "$(TargetDir)$(TargetName).pdb", "$(SolutionDir)XSockets\Plugins\"

Create a class Named “Start” under the Server-project. Copy the content from “MVC-Project\XSockets\devservercode.txt” to this newly created class. Fix namespaces and add reference to the “Server\XSockets\XSockets.Core.dll“. You will also need to add references to “System.Componentmodel.Composition“. The namespaces and using statements should look like this:

using System;
using System.ComponentModel.Composition;
using System.Configuration;
using XSockets.Core.Plugin.MEF;
using XSockets.Core.XSocket.Interface;

namespace Server
{
    public class Start : Composable
    {
        //... ... ...
    }
}

It’s time for the final adjustment. Now lets fix Program.cs. In $MVCApp$\XSockets\DevelopmentServer\HOW_DO_I_DEBUG_MY_HANDLERS.txt you can find a snippet around step 7 in that file. Make the Main method look something like this:

static void Main(string[] args)
{
    try
    {
        new Start();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        if (ex.InnerException != null)
            Console.WriteLine(ex.InnerException.Message);
        Console.ReadLine();
    }
}

It should now be ready to serve our client requests. Fire up the Server and run the “handlers” command and ensure that the “SisoDbHandler” is located in there.

Step 4 – Implement a simple Ping method in our SisoDbHandler

Before wrapping this up, let’s add a simple Ping action in our handler. Again, a handler could be seen as a controller in Asp.Net MVC; and it’s members serving socket calls; could be seen as actions in Asp.Net MVC.

Create a new folder/namespace, and call it “Commands“. Add a class called “PingCommand“. This will serve as our model in.

public interface ICommand {}

public class PingCommand : ICommand
{
    public string Message { get; set; }
}

Create a new folder/namespace, and call it “Results“. Add a class called “PingResult“. This will serve as our model out.

public interface IResult {}

public class PingResult : IResult
{
    public string Message { get; set; }
}

Now, add a member in our SisoDbHandler, and make it look like this:

[HandlerEvent("Ping")]
public void Ping(PingCommand command)
{
    this.AsyncSend(new PingResult { Message = command.Message }, "OnPinged");
}

If you now start the Server and run the “handlers” command, you will see that the SisoDbHandler now accepts calls to a member called “Ping“.

Step 5 – Use the SisoDbClient.js to invoke our Ping member

Now, lets use the added Ping member. Create a simple html-page in the root of our MVC-app. Name it “demo.html“. We need script references to jQuery, XSockets and the SisoDbClient.js libs.

<!DOCTYPE html>
<html>
<head>
	<title>Demo - SisoDb-XSockets</title>
	<script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
	<script src="Scripts/JXSockets-1.0.4.beta.js" type="text/javascript"></script>
	<script src="http://cloud.github.com/downloads/danielwertheim/SisoDb-XSockets/sisodbclient-debug-v0.1.0.js" type="text/javascript"></script>
	
	<script type="text/javascript">
		var my = {};

		$(function () {
			//Hook up client
			my.client = new SisoDbClient("ws://127.0.0.1:4502/SisoDbHandler");
			my.client.logger.enabled = true;
			my.client.connect();

			//Hookup listeners
			my.client.onPinged(function (data) {
				$("<li>").text(data.Message).prependTo("ul:first");
			});

			//Hookup UI to consume client
			$("#ping").on("click", function () {
				my.client.ping($("#pingMessage").val());
			});
		});
	</script>
	<link href="Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
	<fieldset>
		<legend>Ping</legend>
		<label for="pingMessage">Message</label>
		<input type="text" id="pingMessage"/>
		<button id="ping">Ping</button>
	</fieldset>
	
	<ul></ul>
</body>
</html>

Now, start the server and start the MVC-app and browse to the Html-page. Run the command “status” in the server and you should see something like this:

Lets invoke our UI and just send the text: “Test“. If you have the console running, the SisoDbClient.Js will output some logging. You can turn this off by changing this line:

my.client.logger.enabled = false;

That’s it! The next time we will implement a simple model and the CRUD operations.

//Daniel

Benchmarks, SisoDb and RavenDb

This post is an extract from my recently posted post where I reply on criticism against SisoDb from a member in the RavenDb team. You can read it here: http://daniel.wertheim.se/2012/03/11/ranting-is-good-for-you/

First lets make it clear. I have never had any intentions creating a RavenDb vs SisoDb scene, these benchmarks are a result of Mr Itamar Syn-Hershkos criticism on twitter lately, where I feel he hasn’t got all information but mostly talking out of the old design of SisoDb.

Results

Using well known infrastructure in SQL Server, creating data type specific indexes and sets of data for simple key-values SisoDb is fast. And as it seems, actually faster than RavenDb in the measured scenarios below.

Note about deserialization of matches

NOTE! In medium and large set of data, when querying for Trips the result is much bigger that what RavenDb seems to return; where SisoDb returns all the actual matches, hence you can’t compare those times fairly. RavenDb’s 128 returned and deserialized records, vs SisoDb’s 16668 returned and deserialized records.

RavenDb – returning 128 matches

SisoDb – returning all 16668 matches

Memory consumption

Just looking at the client application that runs the tests. When running with Large sets 100.000 customers and 100.000 trips:

SisoDb 116Mb

RavenDb 1.16Gb

Differences

RavenDb and SisoDb are different. RavenDb has lots of concepts like dynamic vs static indexes, stale data, not returning all matching records etc. SisoDb aims at being Simple. E.g it does all work upfront and makes every leaf in your object hierarchy indexed. It doesn’t use any proxies etc. for change tracking etc. SisoDb is trying to be a fast, non magical, lightweight document-oriented provider over SQL-Server. Just take a look at the memory footprints above.

When using RavenDb in the tests below I have not forced wait for stale results in the timer that measures the operations. Hence the real insert time would actually be longer than indicated.

Both providers are used out of the box but with warm up behavior. Before timing any operations; inserts, queries and deletes have been executed so that each system gets a chance to create cache plans etc. Note that I’m not a skilled RavenDb user. I just used it out of the box. That is, no tweaking what so ever with static indexes etc. I couldn’t find any batch insert API in RavenDb; which SisoDb of course has.

Test machine

The machine is a simple laptop running both the server and client.
Windows 7 Ultimate, SQL2012
Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz
8GB RAM
237Gb SSD with 190Gb free, Samsung PM810

Versions

RavenDb: v1.0.701
SisoDb: v10.4.2

Scenarios

The test code is available at GitHub. The scenarios hasn’t much to do with a real life situation and you should test it in your environment.

The test has three modes and each mode works with two different type of documents.

  • Small set of data (1.000 items)
  • Medium set of data (10.000 items)
  • Large set of data (100.000 items)

Test cases

public interface ITestCases
{
	void Warmup(
            Expression&lt;Func&lt;Customer, bool&gt;&gt; customerPredicate, 
            Expression&lt;Func&lt;Trip, bool&gt;&gt; tripPredicate);

	void BatchInsertCustomers(int numOfCustomers);
	void BatchInsertTrips(int numOfTrips);
	void SingleInsertCustomer();
	void SingleInsertTrip();

	long QueryCustomers(Expression&lt;Func&lt;Customer, bool&gt;&gt; predicate);
	long QueryTrips(Expression&lt;Func&lt;Trip, bool&gt;&gt; predicate);

	//Count methods only used after profiling to get number of items inserted
	long CountCustomers();
	long CountTrips();
}

Customer model

public class Customer
{
	public Guid Id { get; set; }
	public int CustomerNo { get; set; }
	public string Firstname { get; set; }
	public string Lastname { get; set; }
	public ShoppingIndexes ShoppingIndex { get; set; }
	public DateTime CustomerSince { get; set; }
	public Address BillingAddress { get; set; }
	public Address DeliveryAddress { get; set; }

	public Customer()
	{
		ShoppingIndex = ShoppingIndexes.Level0;
		BillingAddress = new Address();
		DeliveryAddress = new Address();
	}
}

public class Address
{
	public string Street { get; set; }
	public string Zip { get; set; }
	public string City { get; set; }
	public string Country { get; set; }
	public int AreaCode { get; set; }
}

public enum ShoppingIndexes
{
	Level0 = 0,
	Level1 = 10,
	Level2 = 20,
	Level3 = 30
}

Trip model

public class Trip
{
	public int Id { get; set; }
	public Transport Transport { get; set; }
	public Accommodation Accommodation { get; set; }
	public decimal Price { get; set; }
}

public class Transport
{
	public string DepartureCode { get; set; }
	public string DestinationCode { get; set; }
	public DateTime DepartureDate { get; set; }
	public int Duration { get; set; }
}

public class Accommodation
{
	public string HotelCode { get; set; }
	public string RoomCode { get; set; }
	public DateTime CheckinDate { get; set; }
	public int Duration { get; set; }
}

Customer query predicates
The queries for customers used in the tests.

//Small set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 500 &amp;&amp; c.CustomerNo &lt;= 550
	&amp;&amp; c.DeliveryAddress.Zip == &quot;525&quot;,

//Medium set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 5000 &amp;&amp; c.CustomerNo &lt;= 5500
	&amp;&amp; c.DeliveryAddress.Zip == &quot;5250&quot;,

//Large set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 50000 &amp;&amp; c.CustomerNo &lt;= 55000
	&amp;&amp; c.DeliveryAddress.Zip == &quot;52500&quot;,

Trip query predicate
The query for trips used in the tests.

//Same for all test sets
var dateFrom = TestConstants.BaseLine.AddDays(10);
var dateTo = dateFrom.AddDays(5);

TripPredicate = t =&gt;
	(t.Transport.DepartureDate &gt;= dateFrom
	&amp;&amp; t.Transport.DepartureDate &lt;= dateTo)
	&amp;&amp; t.Accommodation.Duration &gt; 8

Screenshots of each testrun are inlcuded in the main branch at GitHub.

//Daniel

Ranting is good for you

Yet again I’ve ended up on the receiver side of some ranting; and yet again I say “thank you“. Criticism is most welcome. Now lets have a look at some of the opinions.

As you might know I run an open-source project (http://sisodb.com) which is somewhat a document-oriented provider over SQL-Server. It has a provider model and as of now supports: SQL2008, SQL2012 and SQLCE4. But wait that’s for a RDBMS system, right? Yes, and that’s mostly what the ranting is all about. Hence to get some people to pipe down, I guess I could go and write one for MongoDb, but perhaps that isn’t good enough.

Benchmarks

This post was never about benchmarking RavenDb and SisoDb, but of course I have had to show some numbers. Detailed info about the benchmarks is located in the bottom of the post alternatively you could find them here: http://daniel.wertheim.se/2012/03/12/benchmarks-sisodb-and-ravendb/

It all started in May

In May last year I got some most welcomed criticism (available as PDF here) from Mr Itamar Syn-Hershko, to which I wrote a reply. He’s a nice guy from the RavenDb team, that I have had the honor to met and discuss RavenDb and SisoDb with in real life. And lets make it clear: RavenDb seems like an awesome product and has gained great popularity and what would you expect from a product from Mr Ayende & CO.

No, SisoDb is not looking for world domination

SisoDb is not looking for world domination. Features are added as we need them and it’s not a commercial project and I hope it’s not near RavenDb in features, that would be scary. SisoDb is trying to be a simple solution and it’s up to you to deside if it’s enough for some of your scenarios.

One or two things has happened since 16th of May 2011

Since May a lot of things have happened. I have changed my haircut; I’ve gotten kid number two and SisoDb has gone from v2.1.1 to v10.x using semantic versioning; and has been rewritten: http://sisodb.com/wiki/release-notes

This is something I have pointed out in the comments of Itamar’s blog, (as well as in real life). But never mind, facts about how a system actually is designed are probably irrelevant.

March 6th, 2012 – It happened again

A person started to test SisoDb for their needs. Doing some initial testing; and while doing this dared to tweet about it. Then I, as well as some others, re-tweeted and after a while the discussion was started.


[1]: https://twitter.com/#!/CodingInsomnia/status/177041826103037952
[2]: https://twitter.com/#!/CodingInsomnia/status/177048144025100289

A quick pause to reflect on the task of trying things out

Before continuing. Doing what @CodingInsomnia does, is excellent. Whatever solution you chose as your data access component (DAC), You should evaluate it for your X NUM OF CONTEXTS. In one it might shine and in another it might be totally off. Perhaps you should use a document oriented solution in scenario A but in B you might be better off with an OR/M or a key-value store. That is, don’t you dare to ever select only one and make it fit in every solution just because it shines in one. Not with Entity framework, not with NHibernate, RavenDb, MongoDb, SisoDb…. I guess you get the point. Build your own set of facts for your scenarios.

Lets continue…

So, the discussion was started. Now lets just have a quick look at some of the criticizing tweets.


[3]: https://twitter.com/#!/synhershko/status/177140124310704130

Great, neither is SisoDb but in a concurrent world it doesn’t hurt and if I really wanted to focus on it, I would probably make background indexing available as an option to those comfortable with eventual consistency and stale data as in RavenDb. But then again, it’s still not inserted until data for the indexes has been inserted, because before that, it’s not queryable. Hence, SisoDb, as of now, makes all leafs in your object-graph indexed and queryable up front. So when the insert is executed everything is in place with SisoDb. Of course you can tell it not to index everything.

Side note on the JSON serializers

BTW, if RavenDb is truly about performance, why JSON.Net? I guess it’s because it’s flexible and feature rich. SisoDb, on the other hand relies on ServiceStack.Text. Compare benchmarks here: http://theburningmonk.com/benchmarks/ These stats compares the v4.07 release of JSON.Net and as of now there’s a v4.08 release and perhaps it for once outperforms ServiceStack.Text. I would be surprised though.


[4]: https://twitter.com/#!/synhershko/status/177150025175019520

SisoDb, not being a commercial project and all, I would be scarred of myself if SisoDb had all features that RavenDb does, but still, SisoDb does support includes in the same query as well, and yes it will require a join to that referenced structure. But if you really have an use-case with loading lots of documents that refer to eachother in one query; maybe you shouldn’t use documents at all. As with N+1, should that actually be a case in a document DB? Could it be that your instead should have designed your documents for each scenario and accept duplication of data? Don’t know. But a real life document would probably extract parts of the document it refers to and if needed you could follow the reference and dig deeper. And if it’s a problem to do that ONE extra request on ID, then you have a problem.

But, yes, as of today when selecting out your documents, you have to do your projection and aggregation in a yielded data flow. But again. You can model this in your code. Have a denormalizer that works against a document that is designed for your aggregation needs. And BTW, you can use both stored procedures and raw SQL both within and outside SisoDb. So there’s a solution of aggregations etc.


[5]: https://twitter.com/#!/synhershko/status/177150234886021120

Anyone believing any data access solution is THE SOLUTION is always off. You should always evaluate per context and if you don’t, I guess it’s a good thing that RavenDb is the perfect solution and the solution to every problem concerning data access. By saying that, it then doesn’t only outshine both small projects like SisoDb but bigger once to. Like: StarCounterDb, MongoDb, Cassandra, Redis, CouchDb…..


[6]: https://twitter.com/#!/synhershko/status/177150380965244928

So SQL-Server is the most unoptimized database? If we asume this is true; true that the guys at Microsoft has made a complete failure in assembling their database; couldn’t it be that it’s enough in some cases? I do bet my current car (yeah I know it’s only a Ford Mondeo) on that somewhere in the world, there’s a system that is somewhat complex and actually has good performance in their SQL server.


[6]: https://twitter.com/#!/synhershko/status/177150934961487872


[7]: https://twitter.com/#!/synhershko/status/177151141249953793

As I said, lots of things has happened with SisoDb and I’m sure that’s the case with RavenDb as well. And it’s a good thing SisoDb really is normalized then: http://daniel.wertheim.se/2012/01/17/sisodb-v9-0-released/, http://sisodb.com/wiki/core-concepts Don’t really see how I should normalize it more? I mean, as of now every indexed property get’s a key-value with an index optimized for it’s data type. Also, to clarify for some readers,when using a RDBMS like SQL Server you sometimes really have to denormalize your data. It could be setting up a denormalized table or view for the sake of not having to heavy joins when working and e.g doing lots of aggregations on large sets of data.

So I guess SisoDb sucks?

With all these alleged design flaws from Mr Itamar, I do guess that SisoDb sucks. Surely this must be the case, right? Surely there can’t be a case where SisoDb performs well enough. A case where the enterprise needs/wants to stick with SQL Server cause they are familiar and pleased with all the great infrastructure that comes with it. I do respect DBAs and I hope that SisoDb lets them have the opportunity to e.g partion tables; suggest replication to get separate read and write models; or perhaps let a BI person set up a SSIS job to do transformations of the JSON to fact and leaf tables.

An user was also kind enough to point out that SisoDb works great in shared hosting scenarios as well, since SisoDb in itself doesn’t demand lots of resources but relies on the SQL Server. Now I don’t know how that is for other solutions out there, but at least SisoDb works in that environments.

Benchmarks

First lets make it clear. I have never had any intentions creating a RavenDb vs SisoDb scene, these benchmarks are a result of Mr Itamar Syn-Hershkos criticism on twitter lately, where I feel he hasn’t got all information but mostly talking out of the old design of SisoDb.

Results

Using well known infrastructure in SQL Server, creating data type specific indexes and sets of data for simple key-values SisoDb is fast. And as it seems, actually faster than RavenDb in the measured scenarios below.

Note about deserialization of matches

NOTE! In medium and large set of data, when querying for Trips the result is much bigger that what RavenDb seems to return; where SisoDb returns all the actual matches, hence you can’t compare those times fairly. RavenDb’s 128 returned and deserialized records, vs SisoDb’s 16668 returned and deserialized records.

RavenDb – returning 128 matches

SisoDb – returning all 16668 matches

Memory consumption

Just looking at the client application that runs the tests. When running with Large sets 100.000 customers and 100.000 trips:

SisoDb 116Mb

RavenDb 1.16Gb

Differences

RavenDb and SisoDb are different. RavenDb has lots of concepts like dynamic vs static indexes, stale data, not returning all matching records etc. SisoDb aims at being Simple. E.g it does all work upfront and makes every leaf in your object hierarchy indexed. It doesn’t use any proxies etc. for change tracking etc. SisoDb is trying to be a fast, non magical, lightweight document-oriented provider over SQL-Server. Just take a look at the memory footprints above.

When using RavenDb in the tests below I have not forced wait for stale results in the timer that measures the operations. Hence the real insert time would actually be longer than indicated.

Both providers are used out of the box but with warm up behavior. Before timing any operations; inserts, queries and deletes have been executed so that each system gets a chance to create cache plans etc. Note that I’m not a skilled RavenDb user. I just used it out of the box. That is, no tweaking what so ever with static indexes etc. I couldn’t find any batch insert API in RavenDb; which SisoDb of course has.

Test machine

The machine is a simple laptop running both the server and client.
Windows 7 Ultimate, SQL2012
Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz
8GB RAM
237Gb SSD with 190Gb free, Samsung PM810

Versions

RavenDb: v1.0.701
SisoDb: v10.4.2

Scenarios

The test code is available at GitHub. The scenarios hasn’t much to do with a real life situation and you should test it in your environment.

The test has three modes and each mode works with two different type of documents.

  • Small set of data (1.000 items)
  • Medium set of data (10.000 items)
  • Large set of data (100.000 items)

Test cases

public interface ITestCases
{
	void Warmup(
            Expression&lt;Func&lt;Customer, bool&gt;&gt; customerPredicate, 
            Expression&lt;Func&lt;Trip, bool&gt;&gt; tripPredicate);

	void BatchInsertCustomers(int numOfCustomers);
	void BatchInsertTrips(int numOfTrips);
	void SingleInsertCustomer();
	void SingleInsertTrip();

	long QueryCustomers(Expression&lt;Func&lt;Customer, bool&gt;&gt; predicate);
	long QueryTrips(Expression&lt;Func&lt;Trip, bool&gt;&gt; predicate);

	//Count methods only used after profiling to get number of items inserted
	long CountCustomers();
	long CountTrips();
}

Customer model

public class Customer
{
	public Guid Id { get; set; }
	public int CustomerNo { get; set; }
	public string Firstname { get; set; }
	public string Lastname { get; set; }
	public ShoppingIndexes ShoppingIndex { get; set; }
	public DateTime CustomerSince { get; set; }
	public Address BillingAddress { get; set; }
	public Address DeliveryAddress { get; set; }

	public Customer()
	{
		ShoppingIndex = ShoppingIndexes.Level0;
		BillingAddress = new Address();
		DeliveryAddress = new Address();
	}
}

public class Address
{
	public string Street { get; set; }
	public string Zip { get; set; }
	public string City { get; set; }
	public string Country { get; set; }
	public int AreaCode { get; set; }
}

public enum ShoppingIndexes
{
	Level0 = 0,
	Level1 = 10,
	Level2 = 20,
	Level3 = 30
}

Trip model

public class Trip
{
	public int Id { get; set; }
	public Transport Transport { get; set; }
	public Accommodation Accommodation { get; set; }
	public decimal Price { get; set; }
}

public class Transport
{
	public string DepartureCode { get; set; }
	public string DestinationCode { get; set; }
	public DateTime DepartureDate { get; set; }
	public int Duration { get; set; }
}

public class Accommodation
{
	public string HotelCode { get; set; }
	public string RoomCode { get; set; }
	public DateTime CheckinDate { get; set; }
	public int Duration { get; set; }
}

Customer query predicates
The queries for customers used in the tests.

//Small set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 500 &amp;&amp; c.CustomerNo &lt;= 550
	&amp;&amp; c.DeliveryAddress.Zip == &quot;525&quot;,

//Medium set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 5000 &amp;&amp; c.CustomerNo &lt;= 5500
	&amp;&amp; c.DeliveryAddress.Zip == &quot;5250&quot;,

//Large set
CustomerPredicate = c =&gt;
	c.CustomerNo &gt;= 50000 &amp;&amp; c.CustomerNo &lt;= 55000
	&amp;&amp; c.DeliveryAddress.Zip == &quot;52500&quot;,

Trip query predicate
The query for trips used in the tests.

//Same for all test sets
var dateFrom = TestConstants.BaseLine.AddDays(10);
var dateTo = dateFrom.AddDays(5);

TripPredicate = t =&gt;
	(t.Transport.DepartureDate &gt;= dateFrom
	&amp;&amp; t.Transport.DepartureDate &lt;= dateTo)
	&amp;&amp; t.Accommodation.Duration &gt; 8

Screenshots of each testrun are inlcuded in the main branch at GitHub.

Taken to much time

Now, this has taken to much off my time and I really have better things to do. Now, go and improve your projects. If that means stop using SisoDb, then do it. Me, I will go and make things better in SisoDb and other projects.

//Daniel

SisoDb v10.1 Not pre-release anymore

A couple of days ago I wrote about the pre-release of SisoDb. The 10.0 and 10.0.1 releases was only a pre-releases and after using it some adjustments has been made and this release, v10.1 is not a pre-release. The pre-release fulfilled its purpose and cleaned out some “not so great features” and introduces one new feature.

As always the documentation has been updated along with the release notes.

Removed/Changed

The pre-release had replaced ADO.Net transactions for Transaction-scopes. This was done to support parallel inserts of indexes. Since this was something that needed DTC’s and that brought unnecessary complexity to the code-base, it has been removed and the code has reverted back to use ADO.Net transactions. Transaction-scopes are still supported. The ParallelInserts=On|Off support has been removed and will be replaced by BackgroundIndexing=Off|InProc|Service|Custom, which is a coming v10.x feature.

New feature – TimeStamps

SisoDb now supports time-stamps. You enable support for them by adding a single property (see below) to your class. By doing that you enable SisoDb to assign a value to it upon inserts and updates.

public DateTime StructureTimeStamp { get; set; }
//or
public DateTime [ClassName]TimeStamp { get; set; }
//or
public DateTime I[InterfaceName]TimeStamp { get; set; }
//or
public DateTime TimeStamp { get; set; }

The future

New Providers

I have investigated the possibilities of making SisoDb work for MySQL and SQLite and initially I couldn’t see any hinders. I’ve also looked at making it work over MongoDb and again, can’t see any initial hinders there either.

Indexing

I’m also working on letting you configure, per database, the ability of specifying a setting “BackgroundIndexing”:

Off – As it is now. Key-values for querying are inserted in the indexes-tables when you store a structure
InProc – The key-values will be queued as packages and processed in the background. Hence inserts will be faster.
Service – Same as InProc but demands a separate Service to run on the same machine that hosts the database.
Custom – The key-values are queued but nothing is done with them. It’s up to you to process the queue.

Caching- Pull request Wanted

As of v9.1 SisoDb allows you to hook in a cache provider. But there’s yet no public available implementation, but it would be great if someone provided a pull-request so that we could put up a NuGet package for it.

Install via NuGet

Since it’s no pre-release anymore just do

PM> Install-Package SisoDb.Sql2008

PM> Install-Package SisoDb.Sql2012

PM> Install-Package SisoDb.SqlCe4

or if you are one of the lucky soles having used it before:

PM> Update-Package SisoDb.Sql2008

PM> Update-Package SisoDb.Sql2012

PM> Update-Package SisoDb.SqlCe4

//Daniel

SisoDb, v10.0-prerelease – Transactions, updates and concurrencies

Been using SisoDb for the read model in an distributed system using CQRS for a while and while doing this we have identified some features that we needed when handling concurrent updates. Hence that has been the “theme” for this release of SisoDb. Also, the API has been simplified and the sessions are now using transaction scopes instead of plain ADO.Net transactions.

As always the documentation has been updated along with the release notes.

Install Prerelease via NuGet

Note that it’s a prerelease. Hence when installing via NuGet you need to append the “-Pre” suffix.

PM> Install-Package SisoDb.Sql2008 -Pre

PM> Install-Package SisoDb.Sql2012 -Pre

PM> Install-Package SisoDb.SqlCe4 -Pre

Concurrency tokens

From v10.0 you can now chose to include a concurrency token in your model. You do this by adding a member: public Guid|int|long ConcurrencyToken { get; set; }. This will tell SisoDb to re-check against the database before storing the item and ensure that you aren’t storing an older/other version of the document. If you violate this, a SisoDbConcurrencyException will be thrown.

var item = new SimpleItem { Value = "A" };
Database.WriteOnce().Insert(item);
...
...
using (var session = Database.BeginSession())
{
    var refetched = session.GetById<SimpleItem>(item.Id);
    refetched.Value = "B";

    session.Update(refetched);
}

Inline updates

rom v10.0 you can now do “inline updates” and also (optional) provide a proceed condition. This is useful e.g. when using SisoDb in a concurrent and multithreaded environment like in a asynchronous CQRS solution, since it lets you keep down the update-scope and only update if it’s a later message.

using(var session = db.BeginSession())
{
    session.Update<Customer>(
        id, 
        c => c.BonusPoints = bonusPointIncreasedEvent.NewValue);
}

//or

db.UseOnceTo().Update<Customer>(
    id, 
    c => c.BonusPoints = bonusPointIncreasedEvent.NewValue);

and with the proceed clause:

using(var session = db.BeginSession())
{
    session.Update<Customer>(
        id, 
        c => c.BonusPoints = bonusPointIncreasedEvent.NewValue, 
        c => bonusPointIncreasedEvent.Sequence > c.LastSequence);
}

//or

db.UseOnceTo().Update<Customer>(
    id, 
    c => c.BonusPoints = bonusPointIncreasedEvent.NewValue,
    c => bonusPointIncreasedEvent.Sequence > c.LastSequence);

InsertAs – e.g. anonymous types

From v10.0 you can now call InsertAs(object item) where the item doesn’t have to implement any interface or base-class defined by T. The item being passed just need to match the contract in signature, either partially or fully. You could even insert an anonymous type.

db.UseOnceTo().InsertAs<Customer>(new { CustomerNo = "124", Name = "Daniel Wertheim" });

Transaction Scopes

Before v10.0 the transactions explicitly was plain ADO.Net transactions. As of v10.0, under the hood, the Session makes use of transaction-scopes TransactionScope-class but only as long as the targeted storage does support transaction scopes. So, when creating a session:

using(var session = db.BeginWriteSession())
{
    session.InsertMany(customers);
}

It will make a call to Db.ProviderFactory.GetRequiredTransaction() (Db must be of ISisoDbDatabase to have the member ProviderFactory). Underlying, it will create a TransactionScope with the options ReadCommitted and Required. By using Required you can wrap multiple Sessions in an outer TransactionScope and there by getting a larger transaction scope. Note! It’s not recommended to explicitly make use of the TransactionScope class. Instead, use the ProviderFactory.GetRequiredTransaction() or ProviderFactory.GetSuppressedTransaction() methods.

using (var t = TestContext.ProviderFactory.GetRequiredTransaction())
{
    using (var session = TestContext.Database.BeginSession())
    {
        session.InsertMany(new[]
        {
            new IdentityItem {Value = 1},
            new IdentityItem {Value = 2},
            new IdentityItem {Value = 3}
        });
    }

    using (var session = TestContext.Database.BeginSession())
    {
        session.InsertMany(new[]
        {
            new IdentityItem {Value = 4},
            new IdentityItem {Value = 5},
            new IdentityItem {Value = 6}
        });
    }

    //If you want to rollback changes, you can call t.MarkAsFailed()
}

But again. In the simplest case, db.BeginSession() will make use of transactions under the hood, and it’s nothing you should have to take care of.

That’s it for this release. I’m planning on putting together a provider for MySQL and if there’s anyone that want to contrib, don’t hesitate.

//Daniel