3

I'm trying to implement the unit-of-work pattern for mutliple storage types like the windows registry, a database or the app.config but I cannot figure out how to do it. All examples I find use Entity Framework which already is a UoW so it doesn't help much. What I'd like to store is a simple Setting object.

From http://martinfowler.com/eaaCatalog/unitOfWork.html I understand that

A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.

So I probably should start with a class that has two settable properties and one that tells me whether it's dirty and needs an update.

class Setting
{
    private string _value;

    public Setting(string name, string value)
    {
        Name = name;
        _value = value;
    }

    public string Name { get; set; }

    public string Value
    {
        get { return _value; }
        set
        {
            _value = value;
            IsDirty = true;
        }
    }

    public bool IsDirty { get; private set; }
}

then I guess I need a base repository:

abstract class SettingRepository
{
    private readonly List<Setting> _settings = new List<Setting>();

    public abstract IEnumerable<Setting> Get(Setting setting);

    public void Add(IEnumerable<Setting> settings)
    {
        _settings.AddRange(settings);
    }

    public abstract int SaveChanges();
}

and a unit-of-work as SettingContext:

abstract class SettingContext
{
    protected SettingContext(SettingRepository settings)
    {
        Settings = settings;
    }

    public SettingRepository Settings { get; }
}

Now I'm not sure where I should put all the Update/Insert/SaveChanges logic? A database would for example support transaction whereas the windows registry not.

Do I need different repositories for each storage type or do I need different unit-of-work aka contexts for each of them? I'm really confused.


I don't know what exactly I should do next. Maybe I think to much Entity Framework and try to implement it in a too similar way like this:

using(var context = new SettingContext(new RegistryRepository()))
{
    context.Settings.Add(new Setting("Foo", "Bar")); // this should be created
    context.Settings.Add(otherSetting); // this should be updated
    context.SaveChanges();
}
  • You can write to registry in a transactional manner, using the Kernel Transaction Manager component. msdn.microsoft.com/en-us/library/windows/desktop/… – Adrian Iftode Nov 20 '16 at 22:54
  • 2
    A note on patterns - don't try to use patterns because they are patterns. Try to find a solution to solve your problem based on your requirements. Patterns are a consequence of coding logic, not a buffet of building blocks you choose from. – T. Sar Nov 25 '16 at 13:12
  • @ThalesPereira I completely agree. I have never had the need for the UoW before but perhaps it is because I don't entirely understand it. The example with saving settings into various data stores seemed like an easy case to try it out. In my current implementation I use repositories with a common interface and I wanted to implement it the UoW way to see for myself whether I has any advantanges over my current solution. Unfortunatelly I seem to be not the only one who doesn't get it because so far no one could tell how in this example a correct implemention should look like. – t3chb0t Nov 28 '16 at 9:54
  • 1
    @t3chb0t So, really - what you will see in action is not the Unit of Work pattern, it's the code to solve the problem at hand. My Unit of Work code to solve my database needs may not solve your needs, but that doesn't mean my code is wrong. Really, forget patterns while you are coding. Use them later, to see what you did, but not to decide what you should do. – T. Sar Nov 28 '16 at 10:19
  • 1
    @t3chb0t (Also, take anything that comes from Martin Fowler - actually, from everyone, really - with a grain of salt - Fowler is a great programmer, but he is also human and sometimes he puts out some ideas that look great on a teaching book but don't survive contact with all types of business environments.) – T. Sar Nov 28 '16 at 10:24
1

Your approach is fine so far. The "Unit-of-Work" class should get the responsibility to keep track of the changes to your "settings entity" for one "transaction" (it could do this, for example, by keeping a list of commands or changed objects, if there would be more than one object involved), and the abstract repository should provide an abstraction for the CRUD operations (so there will be one concrete repository implementation for each type of storage, that is fine). The "Commit" operation of the "UoW" then just loops over the commands or changed objects and uses the CRUD operations of the injected repo to store the data/changes.

However, if all the data you have to manage is contained in just one settings object, and the update operation is just to write that object into the storage in one transaction, using a "Unit-of-Work" approach is probably overkill. UoW makes more sense if you need some kind of parentheses around a complex transaction, involving multiple objects. For your Settings object, a repo with methods like SaveSettings and LoadSettings is probably sufficient.

  • Ok, great ;-) I actaully have this now as different repositories without an UoW but as I've never implemented UoW yet I thought this example is super easy so if I get how it works with a single entity type then it should be much esier to add more later or such features as change tracking for which UoW seems to be the right choice. – t3chb0t Nov 19 '16 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.