Deveel Repository
Deveel
  • Why Another Repository Pattern Library?
  • The Repository Pattern
  • Getting Started
  • Customize the Repository
  • Multi-Tenancy of Data Sources
  • User Entities
  • Repository Implementations
    • In-Memory Repositories
    • Entity Framework Core Repositories
    • MongoDB Repositories
  • The Entity Manager
    • Caching Entities
Powered by GitBook
On this page
Edit on GitHub

Repository Implementations

PreviousUser EntitiesNextIn-Memory Repositories

Last updated 1 year ago

The Deveel Repository framework comes with some implementations of the Repository pattern.

Data Source
Library

Abstraction Patterns

One of the benefits of using a Repository pattern is the abstraction of the data access mechanism, which allows the implementation of a single paradigm for the management of the data, porting it to the various data storage sources, following the Liskov substitution principle.

For example. the class uses this approach, implementing a superset of functions on top of the IRepository<TEntity> abstraction.

This allows to switch between implementations of IRepository<TEntity>, without affecting the behavior of the consuming class.

Business Data Logic

A design pattern that I recommend is the separation of the overall data logic from the concrete implementation, especially in scenarios of reuse (eg. NuGet libraries).

For example:

Foo.Service.dll

using System;
using Deveel.Data;

namespace Foo {
    public interface IData {
        string? Id { get; }
        byte[] Content { get; }
        string ContentType { get; }
    }
    
    public interface IDataRepository<TData> : IRepository<TData> where TData : class, IData {
        Task<string> GetContentTypeAsync(TData data, CancellationToken cancellationToken = default);
        Task<byte[]> GetContentAsync(TData data, CancellationToken cancellationToken = default);
        Task SetContentAsync(TData data, string contentType, byte[] content, CancellationTyoken cancellationToken = default);
    }
    
    public class DataManager<TData> : EntityManager<TData> where TData : class, IData {
        public DataManager(IDataRepository<TData> repository, IEntityValidator<TData>? validator = null, IServiceProvider? services = null. ILoggerFactory? loggerFactory = null)
            : base(repository, validator, null, null, services, loggerFactory) {
        }
        
        protected IDataRepository<TData> DataRepository => (IDataRepository<TData>)base.Repository;
        
        public Task<OperationResult> SetContentAsync(TData data, string contentType, byte[] content, CancellationToken? cancellationToken = null) {
            ThrowIfDisposed();
            
            try {
                var existingContentType = await DataRepository.GetContentTypeAsync(data, GetCancellationToken(cancellationToken));
                var existingContent = await DataRepository.GetContentAsync(data, GetCancellationToken(cancellationToken));
                if ((existingContentType != null && existingContentType == contentType) &&
                    (existingContent != null && existingContent == content)) {
                    return OperationResult.NotModified;
                }
                
                await DataRepository.SetContentAsync(data, contentType, content, GetCancellationToken(cancellationToken);
                
                // this will invoke the validation before invoking the 
                // Update method of the repository
                return await UpdateAsync(data);
            } catch (Exception ex) {
                Logger.LogError(ex, "Could not set the content");
                return Fail("DATA_ERROR");
            }
        }
    }
}

While in the Foo.Service.MongoDb.dll you can implement a MongoDB-specific access logic

using System;
using Deveel.Data;

namespace Foo {
    public class MongoData : IData {
        public ObjectId? Id { get; }
        string? IData.Id => Id?.ToString();
        public string ContentType { get; set; }
        public byte[] Content { get; set; }
    }
    
    public class MongoDataRepository : MongoRepository<MongoData>, IDataRepository<MongoData> {
        public MongoDataRepository(IMongoDbContext context)
            : base(context) {
        }
        
        public Task SetContenAsync(MongoData data, string contentType, byte[] content, CancellationToken cancellationToken = default) {
            data.ContentType = contentType;
            data.Content = content;
            return Task.CompletedTask;
        }
        
        public Task<byte[]> GetContentAsync(MongoData data, CancellationToken cancellationToken = default) {
            return Task.FromResult(data.Content);
        }
        
         public Task<string> GetContentTypeAsync(MongoData data, CancellationToken cancellationToken = default) {
            return Task.FromResult(data.ContentType);
        }
    }
}

... and in Foo.Service.EF implement the same logic using EntityFramework Core

using System;
using Deveel.Data;

namespace Foo {
    public class DbData : IData {
        public Guid? Id { get; }
        string? IData.Id => Id?.ToString();
        public string ContentType { get; set; }
        public string Content { get; set; }
        byte[] IData.Content => Convert.FromBase64String(Content);
    }
    
    public class EntityDataRepository : EntityRepository<MongoData>, IDataRepository<MongoData> {
        public EntityDataRepository(DataDbContext context)
            : base(context) {
        }
        
        public Task SetContenAsync(DbData data, string contentType, byte[] content, CancellationToken cancellationToken = default) {
            data.ContentType = contentType;
            data.Content = Convert.ToBase64(Encoding.UTF8.GetString(content));
            return Task.CompletedTask;
        }
        
        public Task<byte[]> GetContentAsync(DbData data, CancellationToken cancellationToken = default) {
            return Task.FromResult(Convert.FromBase64(Encoding.UTF8.GetBytes(data.Content));
        }
        
         public Task<string> GetContentTypeAsync(MongoData data, CancellationToken cancellationToken = default) {
            return Task.FromResult(data.ContentType);
        }
    }
}

EntityManager<TEntity>
In-Memory
Entity Framework
MongoDB
Nuget
Nuget
Nuget