Atl.Repository.Standard – Basic Usage

The most common problem that I faced while building any system, no matter how complex or simple it can be, is settings up the data reader and writer for the data store. It does not really matter what you are building, as long you need a data store, you are probably going to face the same following problems –

  1. Most of the features for a data store are same. It is a store, saves data and returns data when queried.
  2. Its redundant but yet, not exactly duplicate. Each system requires slightly different features. For example, one system might require a repository/store that has multi-tenancy support out of the box and thus isolates data as if each tenant’s context is a sandbox, yet, another system might want to do the same, based on the Organization and some other might require the same partition per user.
  3. Supports Inversion of Control.
  4. Supports Parallelism and Concurrency.
  5. Has option to manipulate unit or work patterns, for special cases., etc.

The list goes on ….

In my library Atl.Repository.Standard, I have tried to solve as much problems as possible and will gradually modify it to do what we want it to do.

At the moment of this writing, Atl.Repository.Standard only support basic CRUD operations, i.e. CREATE, READ, UPDATE and DELETE operations. Supports IOC by default.

Basic Uses

Lets setup our POCO object first. These is our domain class –

public abstract class BaseDomain
  public virtual int Id { get; set; }
  public virtual bool IsActive { get; set; }
  public virtual bool IsDeleted { get; set; }
  public virtual bool IsLocked { get; set; }
  public virtual bool IsArchived { get; set; }
  public virtual bool IsSuspended { get; set; }
  public virtual DateTime? CreatedAt { get; set; }
  public virtual DateTime? UpdatedAt { get; set; }

public class Tenant : BaseDomain, IDomain<int>

For demonstration, I will only use one domain class Tenant for now.

Now, lets install the nuget package to setup repository and other classes

Install-Package Atl.Repository.Standard

Once, installed we need to set up the following classes for the repository to function properly –

An Id Generator

The purpose of the id generator is to give an option if you would like use a custom generator which is not database generator. The signature of the id generator looks like –

public interface IKeyGenerator<TKey>
    TKey Generate(IDomain<TKey> obj);
    bool DoesRequireNewKey(TKey currentKey);

    Expression<Func<TDomain, bool>> Equal<TDomain>(Expression<Func<TDomain, TKey>> left, TKey right)
            where TDomain : IDomain<TKey>;

If you are happy with a Guid or intid, the library comes with default implementation of both GuidKeyGenerator and IdentityKeyGenerator. You can just use them right away.

A Domain Injector

One of the strong feature of the library is the DomainInjector. Instead depending on the DatabaseContext class itself and defining and referring all domains before hand, you can load assemblies on the fly and inject domains with this approach.

This class will inject domains when the repository is created.

public class DomainInjector : IDomainInjector
  public void InjectDomain(ModelBuilder modelBuilder)

A System Clock

Atl.Repository.Standard works with a custom clock provider. This gives you options to do TDD in a lot easier way.

As usual, comes with its default implementation of ISystemClock you can just use it right away.

var clock = new DefaultSystemClock()

A Configuration Provider

Same as the Domain Injector, this configuration provider supports DI and can be injected easily. Provides configuration and connectionstring to connect to database.

For example, if we need to use a SQLite database we use –

public class TestConfigurationProvier : IConfigurationProvider
  public string ConnectionString => "";
  public DbContextOptionsBuilder ApplyDatabaseBuilderOptions(DbContextOptionsBuilder optionsBuilder)
    var contectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = "TestDatabase.db" };
    return optionsBuilder.UseSqlite(contectionStringBuilder.ToString());

A Database Context Factory

The purpose of the context factory is to provide a context scope. Put it all together and create a context factory now –

var configurationProvider = new TestConfigurationProvier();
var domainInjector = new DomainInjector();
ContextFactory = new DomainContextFactory(new List<IDomainInjector>() { domainInjector }, configurationProvider);

Now, now we are ready to create our repository and use it –

var repository = new Repository<int>(idGenerator, ContextFactory, new DefaultSystemClock(), null);

Congratulations! Your repository is ready to be used.


Saving and loading items are as simple as –

//saving && updating
var tenant = new Tenant();

var tenants = _repo.GetAll<Tenant>().ToList();

Please keep in mind that, the repository returns IQueryable for GetAll method. So unless you call ToList() it will not execute the method on the data store. This gives you great option to leverage built in features from EF core, such as Include. You can fetch related entries just like you would do for normal EF context . An example Organization model that looks like this –

public class Organization : BaseDomain
     public Tenant Tenant { get; set; }
     public int TenantId { get; set; }

might easily include the referenced model Tenant

var tenants = _repo.GetAll().Include(x => x.Tenant).ToList();

like this or perform a where clause like –

var tenants = _repo.GetAll().Include(x => x.Tenant).Where(x => x.Tenant.Name == "Some Tenant").ToList();

Happy Coding.

One thought on “Atl.Repository.Standard – Basic Usage

Add yours

I would like to say something ...

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at

Up ↑

%d bloggers like this: