OverStore ORM (Obect-Relational Mapper) for Windows, Windows Mobile, Windows CE platform developed with .NET Compact Framework.

OverStore - ORM (object-relational mapper) that supports working with database data represented as CLR classes.

Frequently Asked Questions (FAQ)

OverStore is good because:

  • Fully written on safe managed CLS compliant code using C# (full source code provided).
  • One assembly can be used on devices (smartphones, PDAs) running .NET Compact Framework and on desktop or server running full .NET Framework.
This allows you create one domain model for both server and device applications.
  • Persists POCO (plain old C# objects), does not requires entity classes be marked up with any attributes, inherits any base classes, or implements any interfaces (except some optional features like deferred loading that requires class to implement some interfaces).
This allows you to persist existing domain model without changing it. You even don't need source code to create persistence layer for your classes.
  • Fully documented source code with lot of unit tests.

OverStore is bad because:

  • No LINQ2SQL support (because .NET Compact Framework does not provide required infrastructure for this). LINQ2Collections of course is supported.
  • Some features like deferred (lazy) loading requires class to implement specific interface.
  • All SQL commands used for load or save instances or collections must be preconfigured, there is no way to execute custom SQL command for loading set of object.

Also:

  • Supports lazy entity sequences: entites are read from database due iterating entity sequence. This allows to display on PDA UI list for tables with hundreds of thousands records very quickly and loads data due scrolling (of course, database reader and its underlying database connection still open).
  • Correct works with objects have mutable identifiers, composite identifiers, database-generated identifiers.
  • Does not require any class contract agreements (like properties with predefined names, mandatory Equals() and GetHashCode() methods overrides etc.)
  • Supports complex object hierarchies, including closed graphs, self-references, collection properties.
  • Supports lightweight convenient analog of transaction scopes.
  • Supports persisting of standard .NET generic collections like Collection<T>, List<T> etc. so you don't need to use strange custom collection classes.
  • Allows easy working in 3-tier scenario since supports object attaching: correctly saving arguments of service methods that were not loaded using current session.
  • Don't use runtime code generation and implicit proxy classes, don't modify class hierarchy, so don't make problems due serialization, reflection etc.

Cool features:

  • Error transforming: transform database exception with non-human-readable messages to exceptions with custom text allows you to easy integrate persistence layer to domain model.
  • Create assembly contains configuration once and use it on application server running Microsoft Windows© and Microsoft SQL Server© as well as PDA running MS SQL Server© Compact Edition. Hint:use generics and type parameter for connection type and string parameter for connection string.
  • Create solid 3-tier applications with new attaching features.

5 MINUTES INTRO:


/* Simple example demonstrates OverStore usage basics */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OverStore.Configuration.Builder.Fluent;
using System.Data.SqlServerCe;
using System.IO;
using System.Reflection;
using OverStore.Runtime.Storage;
using OverStore.Configuration.Components;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace OverStore.TutorialAsTest
{
    [TestClass]
    public class FiveMinIntro
    {
        // Here short and simple example of using OverStore

        // Prepare database:
        // CREATE TABLE Animals(Animal_Id int not null primary key identity (1,1), Name nvarchar(150) not null, Is_Predator bit not null)

        // Create class stores data from Animals table:
        public class Animal
        {
            public int Id { get; set; }

            public string Name { get; set; }

            public bool IsPredator { get; set; }
        }

        [TestMethod]
        public void OverStoreFiveMinIntro()
        {
            // Configure OverStore to persists Animal objects in Animals table.
            var dbFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Replace(@"file:///", "")), "TestDb.sdf");
            var connectionString = String.Format("Data Source = '{0}'", dbFileName);
            var configuration = OverStoreFluent.Configure()
                    .LogToConsole()
                    .ConnectToDatabase<SqlCeConnection>(connectionString, ProcessOpenedReadersMode.ForciblyCloseReaders)
                    .MapClassToTable<Animal, int>("Animals") // class, identifier type and table name
                        .MapDbGeneratedKey(
                                "Animal_Id",                                        // Primary key column
                                animal => animal.Id,                                // Get primary key from Animal instance
                                (e, id) => e.Id = id,                               // Apply primary key to Animal instance
                                Component.IdentifierGenerator.Seq<Animal>(-1, -1))  // Sequentially generates temporary primary keys for new Animal objects
                        .MapScalarValue("Name", animal => animal.Name, (animal, name) => animal.Name = name)
                        .MapScalarValue("Is_Predator", animal => animal.IsPredator, (animal, isPredator) => animal.IsPredator = isPredator)
                        .ParameterlessReader(true) // Database query for reader without parameters
                            .WithCommand(Component.AdoCommand.ReadCommand("select * from Animals"))
                            .DelegateIdentifierProvider(r => r.GetInt32("Animal_Id"))
                        .EndReader()
                    .EndTableMapping()
                .End();

            // Add new Animal:
            using (var session = configuration.CreateSession())
            {
                var tiger = new Animal { Name = "Tiger", IsPredator = true };
                var elephant = new Animal { Name = "Elephant", IsPredator = false };
                session.Add(tiger);
                session.Add(elephant);
                session.SaveAll();            // Tiger and elephant are saved to database.
                Assert.AreEqual(1, tiger.Id); // Identifier is generated by database.
            }

            // Check Tiger and Elephant are successfuly added:
            using (var session = configuration.CreateSession())
            {
                var tiger = session.GetByIdentifier<Animal, int>(1);
                Assert.AreEqual(1, tiger.Id);
                Assert.AreEqual("Tiger", tiger.Name);
                Assert.IsTrue(tiger.IsPredator);

                var elephant = session.GetByIdentifier<Animal, int>(2);
                Assert.AreEqual(2, elephant.Id);
                Assert.AreEqual("Elephant", elephant.Name);
                Assert.IsFalse(elephant.IsPredator);
            }

            // Upgrade Tiger to White Tiger
            using (var session = configuration.CreateSession())
            {
                var tiger = session.GetByIdentifier<Animal, int>(1);
                tiger.Id = 123;               // Try to crash OverStore by faking instance primary key.
                tiger.Name = "White Tiger!";
                session.SaveAll();

                var whiteTiger = session.GetByIdentifier<Animal, int>(1);
                Assert.AreSame(tiger, whiteTiger); // Once assigned, object identifier can't be changed.
            }

            // Check Tiger is upgraded to White Tiger:
            using (var session = configuration.CreateSession())
            {
                var tiger = session.GetByIdentifier<Animal, int>(1);
                Assert.AreEqual(1, tiger.Id);
                Assert.AreEqual("White Tiger!", tiger.Name);
                Assert.IsTrue(tiger.IsPredator);
            }

            using (var session = configuration.CreateSession())
            {
                // OverStore DOES NOT support LINQ to SQL, so fetch all animals to list.
                var animals = session.CreateReader<Animal>().ToList();
                // All two animals added before are here.
                Assert.AreEqual(2, animals.Count);
                var tiger = animals.FirstOrDefault(a => a.Name == "White Tiger!");  // It just LINQ to Collections.
                var elephant = animals.FirstOrDefault(a => a.Name == "Elephant");
                Assert.AreSame(tiger, session.GetByIdentifier<Animal, int>(1));    // OverStore has just one instance corresponing to table's row.
                Assert.AreSame(elephant, session.GetByIdentifier<Animal, int>(2)); // No matter how the instance is obtained.
            }
        }
    }
}

Last edited Mar 19, 2011 at 12:38 AM by sergeyt, version 23