LINQ to SQL Repository - Part 1

I needed wanted to create a repository to enable a disconnected LINQ to SQL data tier. I've also put together a cached version, which allows caching of the entities, and automatic updating of the items in the cache and database.

Below is the base repository.


public abstract class BaseRepository<TEntity> where TEntity : class, new() {
public event EventHandler<EntityEventArgs<TEntity>> Adding;
public event EventHandler<EntityEventArgs<TEntity>> Updated;
public event EventHandler<EntityEventArgs<TEntity>> Deleting;
public string ConnectionString { get; set; }

public SiteBuilderApplicationServices AppServices { get; set; }

protected BaseRepository()
: this(WebAppSettings.ConnectionString) {

}

internal BaseRepository(string connectionString) {
ConnectionString = connectionString;
}

protected virtual SBTWebDataContext DataContext {
get {
var db = new SBTWebDataContext(ConnectionString);
return db;
}
}

protected void LogException(Exception ex) {
//TODO: Log Exception
}

/// <summary>
/// Returns a list of entities from the data store.
/// </summary>
/// <returns>IEnumerable of TEntity</returns>
public virtual IEnumerable<TEntity> List() {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
return ApplySort(table.AsQueryable()).ToList();
}
}

/// <summary>
/// Gets a list of TEntity from the data store, using a filter.
/// </summary>
/// <param name="filter">An expression to use to query the data store</param>
/// <returns>IEnumerable of TEntity</returns>
public virtual IEnumerable<TEntity> Find(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter) {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
return ApplySort(table.Where(filter)).ToList();
}
}

protected internal IQueryable<TEntity> Query(DataContext db, System.Linq.Expressions.Expression<Func<TEntity, bool>> filter) {
var table = db.GetTable<TEntity>();
return ApplySort(table.Where(filter));
}

/// <summary>
/// A helper method that is called after the Query method. Override this method in a derieved repository to apply default sorting to the repository.
/// </summary>
/// <param name="query">The query to sort</param>
/// <returns>A sorted IQueryable of <typeparamref name="TEntity"/></returns>
protected virtual IQueryable<TEntity> ApplySort(IQueryable<TEntity> query) {
return query;
}

/// <summary>
/// Gets an entity from the data store.
/// </summary>
/// <param name="id">The ID of the entity to get.</param>
/// <returns>TEntity</returns>
public virtual TEntity Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> selector) {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
return table.Single(selector);
}
}

/// <summary>
/// Gets the first element matching the sequence.
/// </summary>
public virtual TEntity FirstOrDefault(System.Linq.Expressions.Expression<Func<TEntity, bool>> selector) {
try {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
return table.FirstOrDefault(selector);
}
} catch (Exception ex) {
LogException(ex);
throw;
}
}

/// <summary>
/// Checks if the ID is valid on the data store.
/// </summary>
/// <param name="id">The ID to check.</param>
/// <returns>Boolean</returns>
public virtual bool Exists(System.Linq.Expressions.Expression<Func<TEntity, bool>> selector) {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
return table.Where(selector).Count() == 1;
}
}

public virtual TEntity Update(TEntity source) {
try {
using (var db = DataContext) {
Table<TEntity> table = db.GetTable<TEntity>();
ParameterExpression tempParameterExpression;
string keyMethod = db.GetPrimaryKey<TEntity>();
var selector = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(Expression.Property(tempParameterExpression = Expression.Parameter(typeof(TEntity), "x"), keyMethod), Expression.Property(Expression.Constant(source), keyMethod)), new ParameterExpression[] { tempParameterExpression });

TEntity destination = table.Single(selector);
PrepareForUpdate(source, destination);
db.SubmitChanges();
return destination;
}
} catch (Exception ex) {
LogException(ex);
throw;
}
}

/// <summary>
/// Adds an entity to the data store.
/// </summary>
/// <param name="entity">The entity to add</param>
/// <returns>TEntity</returns>
public virtual TEntity Add(TEntity entity) {
EntityEventArgs<TEntity> args = new EntityEventArgs<TEntity>(entity);
OnAdding(args);
if (!args.Cancel) {
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
table.InsertOnSubmit(entity);
db.SubmitChanges();
return entity;
}
} else {
return null;
}
}

/// <summary>
/// Deletes an entity from the data store.
/// </summary>
/// <param name="id">The ID of the entity to delete</param>
/// <returns></returns>
public virtual bool Delete(System.Linq.Expressions.Expression<Func<TEntity, bool>> selector) {
bool deleted = false;
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
var entity = table.FirstOrDefault(selector);
if (entity != null) {
EntityEventArgs<TEntity> args = new EntityEventArgs<TEntity>(entity);
OnDeleting(args);
if (!args.Cancel) {
table.DeleteOnSubmit(entity);
db.SubmitChanges();
deleted = true;
}
}
}
return deleted;
}

public virtual bool DeleteAll(System.Linq.Expressions.Expression<Func<TEntity, bool>> selector) {
bool deleted = false;
using (var db = DataContext) {
var table = db.GetTable<TEntity>();
var entities = table.Where(selector);
entities.ForEach(x => OnDeleting(new EntityEventArgs<TEntity>(x)));
table.DeleteAllOnSubmit(entities);
db.SubmitChanges();
deleted = true;
}
return deleted;
}

protected void PrepareForUpdate(TEntity source, TEntity destination) {
var pkProp = (from member in DataContext.Mapping.GetMetaType(typeof(TEntity)).DataMembers
select member).ToList();

Type entType = typeof(TEntity);
PropertyInfo[] properties = entType.GetProperties().Where(x => x.CanWrite).ToArray();
for (int i = 0; i < properties.Length; i++) {
int ti = i;
var metaDataInfo = pkProp.FirstOrDefault(x => x.Name == properties[ti].Name);
if (metaDataInfo != null) {
bool noprocess = metaDataInfo.IsAssociation | metaDataInfo.IsDbGenerated;

if (!noprocess) {
object value = entType.GetProperty(properties[i].Name).GetValue(source, null);
properties[i].SetValue(destination, value, null);
}
}
}
}

protected virtual void OnAdding(EntityEventArgs<TEntity> e) {
if (Adding != null) {
Adding(this, e);
}
}

protected virtual void OnUpdated(EntityEventArgs<TEntity> e) {
if (Updated != null) {
Updated(this, e);
}
}

protected virtual void OnDeleting(EntityEventArgs<TEntity> e) {
if (Deleting != null) {
Deleting(this, e);
}
}
}

0 comments: