none
Repository and Unit of Work impelementation help

    Question

  • I am trying to use a Repository pattern to access my Azure Storage Tables. 

    I am basing much off of https://github.com/Boggin/WindowsAzureRepository but it is pretty old and used pre 2.0 stuff.

    My issue is in creating a unit of work.

    From what I read, the Unit of Work in Table Storage is basically a TableBatchOperation, which is limited to a single table and a single partition key and 100 entities under 4MB of data? 

    Here's is my issue and perhaps someone has some architectural suggestions:

    My unit of work basically wraps a TableBatchOperation

    public TableStorageContext(string connectionString = null)
            {
                this.SetupContext();
                
            }
    
            public void Commit()
            {
                try
                {                
                    // Commit the batch
                    this.Table.ExecuteBatch(this.Batch);
                }
                catch (DataServiceRequestException exception)
                {
                    var dataServiceClientException = exception.InnerException as DataServiceClientException;
                    if (dataServiceClientException != null)
                    {
                        if (dataServiceClientException.StatusCode == (int)HttpStatusCode.Conflict)
                        {
                            return;
                        }
                    }
    
                    throw;
                }
            }
    
            public void Save(TableEntity entity)
            {
                this.Batch.InsertOrReplace(entity);
            }
    
            public void Delete(TableEntity entity)
            {
                this.Batch.Delete(entity);
            }

    So, the idea is I create a unit of work, and pass that to a repository or repositories.

    var context = new TableStorageContext();
    var entityRepository = new EntityRepository(context);

    My base repository class has this constructor:

    public RepositoryBase(IUnitOfWork context, string tableName)


    Essentially I am creating a subclass of this for each "Entity" type. Maybe this is part of my problem and the repository should be for a table. Here is an example:

    public EntityRepository(IUnitOfWork context) : base(context, "table")
    {
        ((TableStorageContext)context).Table = this.Table;
    }
    
    public void Save(Entity entity)
    {
        // TODO: check for more than 100 batch operations
        // should probably be done in the UoW class?
        this.Context.Save(entity);
    }
    
    public void Delete(Entity entity)
    {
        this.Context.Delete(entity);
    }

    So, the unit of work wraps the TableBatchOperation, however in order to execute that I need the CloudTable instance. That gets created in the RepositoryBase, notice how the table name is passed. This is the only way the unit of work can execute the batchoperation against the table.

    I think the EnityRepository should know what table that entity should be stored in rather than me doing something like:

    var contex = new TableStorageContext(tablename)

    because that breaks the encapsulation. Also, if I have a second entity that is stored in the same table I want to use the same unit of work. I think I will have the UoW throw if a repo trys to set the context.Table with a different table than already set and also throw is a Save/Delete is called and the PartitionKey doesn't match those already in the UoW.

    So any suggestion on a better way to do this without having the circular reference. I think the UoW should be creating the table, but I'm not sure how it would know what table to get a reference too since it is Generic. Creating a UoW class for each table seems like overkill... also the client code would have to know which UoW class to use for each entity or entities which once again defeats the purpose, exposing data layer info in the business layer.

    Thanks in advance for any ideas.


    • Edited by PilotBob Thursday, December 17, 2015 4:56 PM
    Thursday, December 17, 2015 4:56 PM

All replies