Reputation: 6095
I have .net core rest api, which contains hybrid structure in which it only contains repositories and not the service layer.
Now, there is one issue that I am facing with base repository and main structure. let me explain the issue first.
So, consider one entity. let's say Product and below is the definition for that entity. this entity has one base class called FullAuditedEntity.
[Table(name: "Products")]
public class Product : FullAuditedEntity
{
public string Name { get; set; }
}
public class FullAuditedEntity: IFullAuditedEntity
{
public FullAuditedEntity() { }
[Key]
public virtual int Id { get; set; }
}
public interface IFullAuditedEntity
{
int Id { get; set; }
}
The Base repository and it's interfaces are as below.
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IFullAuditedEntity, new()
{
private readonly ApplicationContext context;
public EntityBaseRepository(ApplicationContext context)
{
this.context = context;
}
public virtual IEnumerable<T> items => context.Set<T>().AsEnumerable().OrderByDescending(m => m.Id);
public virtual T GetSingle(int id) => context.Set<T>().FirstOrDefault(x => x.Id == id);
}
public interface IEntityBaseRepository<T> where T : class, new()
{
IEnumerable<T> items { get; }
T GetSingle(int id);
}
So, my Product repository will be like this.
public interface IProductRepository : IEntityBaseRepository<Product> { }
public class ProductRepository : EntityBaseRepository<Product>, IProductRepository
{
private readonly ApplicationContext context;
public ProductRepository(ApplicationContext context) : base(context: context)
{
this.context = context;
}
}
Now, up-to here everything is good, I can access this repository in controllers and can perform the actions that are listed in base class.
Issue I am facing : So with this structure, If I tries to add any new entity without FullAuditedEntity (see Product entity above, I have base class full audited entity over there), my structure of repository fails and it gives error.
let's say if I tries to add new entity Implementation, and this new entity has a random Id, so I do not want to inherit the FullAuditedEnitity base class. now in this case most of the thing will work fine but when I will try to create repository for Implementation entity, it will give generic error. see below snap of that.
What I tried so far...
I was thinking to create a parallel Base repository which does not inherit FullAuditedEntity as a generic class but I am not sure if it's best practice or not. also my concern is that what if I am doing any mistake in my current structure of repository pattern and Dependency injection?
Any help world be best and really appreciated.
Thank you in advance for your time.
Upvotes: 2
Views: 1475
Reputation: 38094
Repositories are usually mapped to database tables. Database table should always have some column which can uniquely identify the row in table and it is common practice to call this column as Id
. So you correctly implemented your FullAuditedEntity
as there is Id
property. However, your Id
has always type of int
. I suggest you to use the following construction and then your Id
would be any type of struct such as int
, decimal
, Guid
, and etc:
/// <summary>
/// Abstraction of the Entity
/// </summary>
public interface IEntity
{
object Id { get; set; }
}
/// <summary>
/// Base class for IDs
/// </summary>
public abstract class Entity<T>: IEntity where T: struct
{
public T Id { get; set; }
object IEntity.Id
{
get { return Id; }
set {
Id = (T)value;
}
}
}
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntity, new()
{
// The code is omitted for the brevity
}
In addition, try to avoid entities without Id
like Implementation
as in future you will have to figure out how to find rows without Id
in your database table.
UPDATE:
If you do not want to inherit FullAuditedEntity
, then you can create BaseRepository<T>
and then derive it in the EntityBaseRepository
.
public abstract class BaseRepository<T> : IEntityBaseRepository<T> where T : class, new()
{
public virtual IEnumerable<T> items => throw new NotImplementedException();
public virtual T GetSingle(int id)
{
throw new NotImplementedException();
}
}
public class EntityBaseRepository<T> : BaseRepository<T> where T : class
, IFullAuditedEntity, new()
{
public override IEnumerable<T> items => base.items;
public override T GetSingle(int id)
{
return base.GetSingle(id);
}
}
and then your Implementation
repository:
public interface IImplementationRepository : IEntityBaseRepository<Implementation> { }
public class ImplementationRepository: BaseRepository<Implementation>
, IImplementationRepository
{
public override Implementation GetSingle(int id)
{
return base.GetSingle(id);
}
}
UPDATE 1:
In my view, it is better to use services(Service layer
) which consume ITRepository<T>
.
Because it gives to you new abilities such as:
Add some calculations on data which got by Repository
Remap your entities which are pulled by the Repository
It is one additional layer of decoupling. So when you edit your service layer, then you don't need to edit Repository layer and then recompile your assembly
Upvotes: 2