patterncsharpMinor
Abstract repository implementation
Viewed 0 times
implementationabstractrepository
Problem
I have a repository abstract class that encapsulates pretty much all of the CRUD functionality:
```
public abstract class DataRepository : IRepository
where T : class
{
public DataContext Context { get; private set; }
public TransactionScope Transaction { get; private set; }
///
/// A function that compares the keys for fetching a single item, for example:
/// return item1.Id == item2.Id (as an anonymous delegate).
///
public Func KeyCompare { get; private set; }
///
/// Creates a new data repository.
///
///
///
///
/// A function that compares the keys for fetching a single item, for example:
/// return item1.Id == item2.Id (as an anonymous delegate).
///
public DataRepository(DataContext context, TransactionScope scope, Func keyCompare)
{
Context = context;
Transaction = scope;
KeyCompare = keyCompare;
}
public virtual T Item(T item)
{
return Items().SingleOrDefault(e => KeyCompare(e, item));
}
public virtual IEnumerable Items()
{
return DataTable.AsEnumerable();
}
protected virtual Table DataTable { get { return Context.GetTable(); } }
///
/// A method that updates the non-key fields of an existing entity with those of specified .
/// Called by the method.
///
/// The existing record to update.
/// A object containing the values to update object with.
///
protected abstract void UpdateExisting(T existing, T item);
///
/// A method that updates an existing item or creates a new one, as needed.
///
/// The entity containing the values to be saved.
public virtual void Save(T item)
{
var existing = Item(item);
if (existing != null)
{
UpdateExisting(existing, item);
}
else
{
DataTable.InsertOnSubmit(item);
}
Context.SubmitChanges();
}
///
///
```
public abstract class DataRepository : IRepository
where T : class
{
public DataContext Context { get; private set; }
public TransactionScope Transaction { get; private set; }
///
/// A function that compares the keys for fetching a single item, for example:
/// return item1.Id == item2.Id (as an anonymous delegate).
///
public Func KeyCompare { get; private set; }
///
/// Creates a new data repository.
///
///
///
///
/// A function that compares the keys for fetching a single item, for example:
/// return item1.Id == item2.Id (as an anonymous delegate).
///
public DataRepository(DataContext context, TransactionScope scope, Func keyCompare)
{
Context = context;
Transaction = scope;
KeyCompare = keyCompare;
}
public virtual T Item(T item)
{
return Items().SingleOrDefault(e => KeyCompare(e, item));
}
public virtual IEnumerable Items()
{
return DataTable.AsEnumerable();
}
protected virtual Table DataTable { get { return Context.GetTable(); } }
///
/// A method that updates the non-key fields of an existing entity with those of specified .
/// Called by the method.
///
/// The existing record to update.
/// A object containing the values to update object with.
///
protected abstract void UpdateExisting(T existing, T item);
///
/// A method that updates an existing item or creates a new one, as needed.
///
/// The entity containing the values to be saved.
public virtual void Save(T item)
{
var existing = Item(item);
if (existing != null)
{
UpdateExisting(existing, item);
}
else
{
DataTable.InsertOnSubmit(item);
}
Context.SubmitChanges();
}
///
///
Solution
Repositories for
Repositories may not know about anything their context or transaction scope (and they can't be saved directly) these are different story which can be told by an UnitOfWork instance:
Table
The Table property ends up with a leaky abstraction and not all repository need a concrete table.
KeyCompare
Nice idea but it will not work as expected becouse it's a
AsEnumerable()
Imagine a reporitory with 20 billion entities which are stored in a SQL database. What will the above expression mean: download all entities and then query them somehow. Avoid calling the .AsEnumerable an similar methods (.ToArray()) before the final query statement.
Items()
God why? The reporitory should represent what you tried with this method but not an IEnumerable but an IQueryable so a repository must implement this interface. But in this way you cold only query your entities but not add/remove them. Need other methods in a common interface but before creating our own check out the IObjectSet interface from the framework it's perfect for a repository.
- Add objects
- Remove objects
- Query objects (no named queries like GetById)
Repositories may not know about anything their context or transaction scope (and they can't be saved directly) these are different story which can be told by an UnitOfWork instance:
class UnitOfWork : IDisposable
{
public void Dispose() {} // Rollback
public void Commit() {}
}Table
The Table property ends up with a leaky abstraction and not all repository need a concrete table.
KeyCompare
Nice idea but it will not work as expected becouse it's a
Func<> and it can not be translated for example into a SQL query. You should return an Expression> and you can apply that as a simple method call no need other expression becouse it will not be translated and maybe you will end up with an exception:.SingleOrDefault(KeyCompare);AsEnumerable()
public virtual IEnumerable Items()
{
return DataTable.AsEnumerable();
}Imagine a reporitory with 20 billion entities which are stored in a SQL database. What will the above expression mean: download all entities and then query them somehow. Avoid calling the .AsEnumerable an similar methods (.ToArray()) before the final query statement.
Items()
God why? The reporitory should represent what you tried with this method but not an IEnumerable but an IQueryable so a repository must implement this interface. But in this way you cold only query your entities but not add/remove them. Need other methods in a common interface but before creating our own check out the IObjectSet interface from the framework it's perfect for a repository.
Code Snippets
class UnitOfWork : IDisposable
{
public void Dispose() {} // Rollback
public void Commit() {}
}.SingleOrDefault(KeyCompare);public virtual IEnumerable<T> Items()
{
return DataTable.AsEnumerable();
}Context
StackExchange Code Review Q#25250, answer score: 4
Revisions (0)
No revisions yet.