A repository represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability. [...] For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type.
Eric Evans - Domain Driven Design
Most repository patterns contain many query methods, and they are often nearly identical to the DbContext class. Unlike the norm, the Eiffel framework follows a collection-oriented repository approach."
Each repository should expose a single aggregate, and the maintenance of the entities or value objects should be handled by the owner aggregate.
/// <summary>/// IRepository interface/// </summary>/// <typeparamname="TAggregate">The type of aggregate</typeparam>/// <typeparamname="TIdentity">The tpye of aggregate identity</typeparam>/// <typeparamname="TKey">The type of database primary key</typeparam>publicinterfaceIRepository<TAggregate,TIdentity,TKey>whereTKey:struct,IEquatable<TKey>whereTIdentity:classwhereTAggregate:Aggregate<TIdentity,TKey>{ /// <summary> /// Gets record from database /// </summary> /// <paramname="identity">Aggregate</param> /// <paramname="cancellationToken">Cancellation token</param>Task<TAggregate> GetAsync(TIdentity identity,CancellationToken cancellationToken =default); /// <summary> /// Adds record to database /// </summary> /// <paramname="aggregate">Aggregate identifier</param> /// <paramname="cancellationToken">Cancellation token</param> /// <returns>Record from database</returns>TaskAddAsync(TAggregate aggregate,CancellationToken cancellationToken =default); /// <summary> /// Commit changes to database /// </summary> /// <paramname="aggregate">Aggregate</param> /// <paramname="cancellationToken">Cancellation token</param>TaskSaveChangesAsync(TAggregate aggregate,CancellationToken cancellationToken =default);}