HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

UnitOfWork, removing abstraction of abstraction (Repository)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
unitofworkabstractionrepositoryremoving

Problem

I'm creating a small project, but in the past I've used a Repository pattern for it, and it just seemed too bloated. I ended up having repo classes with huge amounts of queries. I'm trying to move away from that. I invite you to critique/help/guide me on my journey to less abstraction:

Note: I like the syntax style of Simple.Data and "Fluentness" of FluentApi. So my naming/style is inspired by them.

I start off with an IUnitOfWork Interface:

public interface IUnitOfWork : IDisposable
{
    void Save();
    IDbSet Set() where T : class;
}


My DB Context (pretty standard):

public partial class MyDbContext : DbContext, IUnitOfWork
{
    public MyDbContext() : base("DBConnection") { }

    public new IDbSet Set() where T : class
    {
        return base.Set();
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UsersMap());
    }
    public void Save()
    {
        SaveChanges();
    }
}


A Query object/service:

public class UserService : IService
{
    private readonly IUnitOfWork unitOfWork;

    public UserService(IUnitOfWork _u)
    {
        this.unitOfWork = _u;
    }
    public string GetUserName(string Name)
    {
        return unitOfWork.Set().Single(s => s.Name == Name).UserName;
    }

}


Here's my Database Class (name inspired by Simple.Data):

public sealed partial class Database
{
    private readonly IUnitOfWork context;

    public Database(IUnitOfWork _context = null)
    {
        if (_context == null)
            this.context = new MyDbContext();
        else
            this.context = _context;
    }

    public static Database Open()
    {
        return new Database();
    }

    // I may move these into a separate file:
    public UserService Users { get { return new UserService(context); } }
}


Usage:

var userName = Database.Open().Users.GetUserName("John");
Console.WriteLine(userName);


This is all fine and good for sim

Solution

I realize you said


my naming/style is inspired by them.

But I would still point out some of your naming conventions which don't align with C#s.

-
Method/Function level variables should be camelCase instead of PascalCase

public string GetUserName(string Name)
public string GetUserName(string name)


-
Same as before, and as a note _underscores should only be used for class level variables.

public UserService(IUnitOfWork _u)
public UserService(IUnitOfWork u)


-
Not required, but a common practice is also that you do indeed use underscores for class level variables

private readonly IUnitOfWork unitOfWork;
private readonly IUnitOfWork _unitOfWork;


Make sure you are disposing(closing) your database object. I presume by the way you have your class setup that when your database object is disposed it will close, in which case I would recommend using the using keyword. Which would make your above code look more like this in practice.

using(var database = Database.Open())
{
    var userName = database.Users.GetUserName("John");
    var userFirstName = database.Users.GetFirstName("john123");
}


This ensures that you are always closing your connection in the end.

Be careful when debugging your code, and remember (depending on your db setup) if you pause the debug in your code while the connection is open, you wont be able to use the database. Also if you have any plans to do mulithreading with this you'll want to use locks.

Code Snippets

public string GetUserName(string Name)
public string GetUserName(string name)
public UserService(IUnitOfWork _u)
public UserService(IUnitOfWork u)
private readonly IUnitOfWork unitOfWork;
private readonly IUnitOfWork _unitOfWork;
using(var database = Database.Open())
{
    var userName = database.Users.GetUserName("John");
    var userFirstName = database.Users.GetFirstName("john123");
}

Context

StackExchange Code Review Q#51364, answer score: 5

Revisions (0)

No revisions yet.