I’m setuping a C# Asp.Net Core Api that will grow quite a bit in the future. So I’m trying to respect the Clean Code architecture, with my domain in the center without any dependences and everything around:
public abstract class Entity
{
public Guid Id { get; set; }
}
I’m currently implementing the repositories. My issue is that for mongoDb, it seems mandatory to either provide the [BsonId]
attribute, either use the BsonId in my entities. But that implies adding a mongoDb reference in my entity project, which I’m not a big fan.
public interface IRepository<TDocument> where TDocument : Entity
{
IQueryable<TDocument> AsQueryable();
IEnumerable<TDocument> FilterBy(
Expression<Func<TDocument, bool>> filterExpression);
IEnumerable<TProjected> FilterBy<TProjected>(
Expression<Func<TDocument, bool>> filterExpression,
Expression<Func<TDocument, TProjected>> projectionExpression);
Task<TDocument> FindOne(Expression<Func<TDocument, bool>> filterExpression);
Task<TDocument> FindById(Guid id);
Task InsertOne(TDocument document);
Task InsertMany(ICollection<TDocument> documents);
Task ReplaceOne(TDocument document);
Task DeleteOne(Expression<Func<TDocument, bool>> filterExpression);
Task DeleteById(Guid id);
Task DeleteMany(Expression<Func<TDocument, bool>> filterExpression);
}
In the example I found on Clean Architecture, they are mostly using entity framework, which doesn’t require absolutely attributes to work.
I could imagine doing another class and using AutoMapper to map between each other, but that seems cumbersome, since I always want to persist everything that are in my business object, and that could lead to some errors.
Isn’t there a way to indicate per collection(or even globally) what is the Id in the repository or when saving ?
2
Answers
You could use the "BsonClassMap":
Reference: https://mongodb.github.io/mongo-csharp-driver/2.14/reference/bson/mapping/
The above solution using static
BsonClassMap
should allow you to identify your Id member without "polluting" your domain.One word of advice, for your own sanity: as an architect, you’ll need to pick and choose which rules you follow religiously, and where it makes sense to make exceptions.
You may find on occasion that a low-risk package reference will make your life considerably easier, whether it be something for data annotations, or a package that gives you Guard clauses or the Specification pattern, etc… I wouldn’t be afraid to break the rule or to embrace some anti-patterns when carefully and thoughtfully considered, and you know the reason WHY it is an anti-pattern.
If you were suggesting adding a dependency to something that was not lightweight, I might suggest you never do it. However, there are certain packages that are intentionally compact, and adding them to your Core/Domain project shouldn’t bring shame to your family name. 🙂
Happy coding!