API for Generic Repository Pattern Implementation (base interfaces)

Development API (code)
Table of Contents
Summary

Source code for the implementation of the namespace DesignPatterns.Repository.Generic.


Operations
IReadOnlyRepository.cs

The generic interface exposes public methods for reading domain entities from a data store, namelly:
i) Read a single entitiy based on the entiity key;
ii) Read multiple entiities based on well-defined filters based on Specification objects or Query Object objects, This way there is
no need to instantiate a derived class for a specific entity which would include methods like GetByXXX.

How to do it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Linq.Expressions;
using DesignPatterns.QueryObject;
using DesignPatterns.Specification.Linq;

namespace DesignPatterns.Repository.Generic
{
    /// <summary>
    /// Generic repository interface for reading domain entities from a data store.
    /// </summary>
    /// <typeparam name="TKey">Type of the primary key</typeparam>
    /// <typeparam name="TEntity">Domain entity type</typeparam>
    /// <typeparam name="IDBContext">Session or data context encapsulated within a unit of work object</typeparam>
    public interface IReadOnlyRepository<TKey, TEntity,IDBContext>
        where TEntity : class, IEntityKey<TKey>
        where IDBContext: class
    {
        /// <summary>
        /// Load entity given its identifier.
        /// </summary>
        /// <param name="pId">Entity identifier</param>
        /// <returns></returns>
        TEntity GetById(TKey pId);

        /// <summary>
        /// Search entities based on a query object. Ordering options are configured through the <see cref="IQueryResult"/> return object.
        /// </summary>
        /// <param name="pQuery">Query object that encapsulates a complex query</param>
        /// <returns>Encapsulates retrieved entities within a dedicated result object</returns>
        IQueryResult<TEntity> Find(IQuery<TEntity, IDBContext> pQuery);

        /// <summary>
        /// Search entities based on a query object. Ordering options are configured through the <see cref="IQueryResult"/> return object.
        /// <note>Only applicable to IQueryable LINQ Providers</note>
        /// </summary>
        /// <param name="pSpecification">Specification object that encapsulates a domain-oriented query</param>
        /// <returns>Encapsulates retrieved entities within a dedicated result object</returns>
        IQueryResult<TEntity> Find(ISpecification<TEntity> pSpecification);

        /// <summary>
        /// Generic search method based on LINQ lambda expressions.
        /// <note>Only applicable to IQueryable LINQ Providers</note>
        /// </summary>
        /// <param name="pPredicate"></param>
        /// <returns></returns>
        IQueryable<TEntity> Find(Expression<Func<TEntity,bool>> pPredicate);
    }
}
IPersistentRepository,cs

The generic interface exposes public methods for CUD operations with domain entities on a data store, namelly:
i) Add a single entitiy to the data store;
ii) Add multiple entiities to the data store;
iii) Delete a saved single entitiy from the data store;
iv) Delete saved multiple entities from the data store;
v) Attach or de-attach a single entity> to or from the current session or data context

How to do it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Linq.Expressions;
using DesignPatterns.QueryObject;
using DesignPatterns.Specification.Linq;

namespace DesignPatterns.Repository.Generic
{
    /// <summary>
    /// Generic repository interface for writing domain entities on a data store.
    /// </summary>
    /// <typeparam name="TEntity">Domain entity type</typeparam>
    /// <typeparam name="IDBContext">Session or data context encapsulated within a unit of work object</typeparam>
    public interface IPersistentRepository<TKey, TEntity, IDBContext>
        where TEntity : class, IEntityKey<TKey>
        where IDBContext : class
    {
        /// <summary>
        /// Add a new entity to the data store.
        /// <note>Make persistent a transient object</note>
        /// </summary>
        /// <param name="pEntity">Entity to insert</param>
        /// <returns>Returns the entity object with the it's identifier populated</returns>
        TEntity Add(TEntity pEntity);

        /// <summary>
        /// Adds a collection of new entities to the data store.
        /// <note>Make persistent a collection of transient objects</note>
        /// </summary>
        /// <param name="pEntities">Collection of entities to insert</param>
        /// <returns>Returns a logical value indicating if the operation ended successfully</returns>
        bool Add(IEnumerable<TEntity> pEntities);

        /// <summary>
        /// Attach an existent entity to the current session or data context.
        /// </summary>
        /// <param name="pEntity">Entity to attach</param>
        /// <param name="pIsModified">Indicates if the contents of the entity object was changed during the disconnected period</param>
        /// <remars>Throws an exception if an unexpected error occurs</remars>
        void Attach(TEntity pEntity, bool pIsModified);

        /// <summary>
        /// De-attach an existent entity from the current session or data context.
        /// </summary>
        /// <param name="pEntity">Entity to dettach</param>
        /// <remars>Throws an exception if an unexpected error occurs</remars>
        void DeAttach(TEntity pEntity);

        /// <summary>
        /// Delete an existent entity from the data store.
        /// </summary>
        /// <param name="pEntity">Entity to delete</param>
        /// <remars>Throws an exception if an unexpected error occurs</remars>
        void Delete(TEntity pEntity);

        /// <summary>
        /// Deletes a collection for existent entities from the data store.
        /// </summary>
        /// <param name="pEntities">Collection of entities to delete</param>
        /// <returns>Returns a logical value indicating if the operation ended successfully</returns>
        bool Delete(IEnumerable<TEntity> pEntities);
    }
}
IEntityKey.cs

This interface makes possible to have a domain entiity with an identifier property named Id and this property can be a numeric or string value.

How to do it
namespace DesignPatterns.Repository.Generic
{
    public interface IEntityKey<TKey>
    {
        TKey Id { get; }
    }
}
References

[1] Refer to this and this articles for Specification pattern implementation
[2] Refer to this article for Query Object pattern implementation