public async Task<TEntity> GetByIdAsync(int id) {
return await Context.FindByAsync(id);
}
and
public IQueryable<TEntity> GetById(Expression<Func<TEntity, int>> predicate) {
return Context.Where(predicate).FirstOrDefault;
}
I'm new to repositories and looking for tutorials and now kinda know what it does but the Task struck me. Between the two which is more preferred? I know it's a stupid question but it would help me understand them better. Any help would be much appreciated. Thanks!
First to your question:
GetByIdAsync: is used to load the data asynchrone from the database, If you have a lot of data for example you have to load about 10000 entries from database then this method it will be the right choice(You can also use bulk operation).
GetById: synchrone load the data from the DB this method is good if your query take just a few milliseconds and does not be called a lot of times from the same thread.
How to use them:
var employee= await new EmployeeRepository.GetByIdAsync(1);---> your method(caller) must be here also Async otherwise, you have to use task.
var employee= new EmployeeRepository.GetById(1);
If your Repository class return IQueryable then you have to do ToList.First();
You need Entity framework 6 or later =>> support of Async.,
otherwise you have to do it by your self!
Example: Let say your business object:
public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
}
// Now using this we will have a simple context class.
public class HRContext : DbContext
{
public DbSet<DomainClasses.Employee> Employees { get; set; }
}
// After that, define the repository interface IEmployeeRepository.
public interface IEmployeeRepository : IDisposable
{
IQueryable<Employee> All { get; }
IQueryable<Employee> AllAsync { get; }
IQueryable<Employee> AllIncluding(params Expression<Func<Employee, object>>[] includeProperties);
Employee Find(int id);
Employee FindAsync(int id);
void InsertOrUpdate(Employee employee);
void Delete(int id);
void Save();
}
// Then the Repository class called EmployeeRepository.
public class EmployeeRepository : IEmployeeRepository
{
HRContext context = new HRContext();
public IQueryable<Employee> All
{
get { return context.Employees; }
}
public IQueryable<Employee> AllIncluding(params Expression<Func<Employee, object>>[] includeProperties)
{
IQueryable<Employee> query = context.Employees;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public Employee Find(int id)
{
return context.Employees.Find(id);
}
public void InsertOrUpdate(Employee employee)
{
if (employee.Id == default(int)) {
// New entity
context.Employees.Add(employee);
} else {
// Existing entity
context.Entry(employee).State = EntityState.Modified;
}
}
public void Delete(int id)
{
var employee = context.Employees.Find(id);
context.Employees.Remove(employee);
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
I get the soruce code from :
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
For example for a generic repository:
public interface IGenericRepository<T> where T : class {
IQueryable<T> GetAll();
IQueryable<T> GetAllAsync();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
IQueryable<T> FindByAsync(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
void Edit(T entity);
void Save();
}
Where T is the base entity for all your entities.
here is the complete generic example:
http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle
For better separation of concern you can also combine the repository pattern with unit of work as described by Martin Fowler book:
http://martinfowler.com/eaaCatalog/unitOfWork.html
Those two pieces of code do different things.
First piece finds a single entity.
var user = await new Repo<User>.GetByIdAsync(12);
Second piece executes the where clause and returns the first element or null. It is badly named because it does not actually force searching by Id.
var user = new Repo<User>.GetById(u => u.Username=="Bob");
The task is there to support .NET 4.5 await and async commands.
Related
I've created application asp.net using a generic repository and Entity Framework.
The abstract class has this code:
public interface IGenericRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
void Edit(T entity);
void Save();
}
and the GenericRepository class contains the following code:
public abstract class GenericRepository<C, T> : IGenericRepository<T> where T : class where C : DbContext, new()
{
private C _entities = new C();
public C Context {
get { return _entities; }
set { _entities = value; }
}
public virtual IQueryable<T> GetAll() {
IQueryable<T> query = _entities.Set<T>();
return query;
}
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate) {
IQueryable<T> query = _entities.Set<T>().Where(predicate);
return query;
}
public virtual void Add(T entity) {
_entities.Set<T>().Add(entity);
}
public virtual void Delete(T entity) {
_entities.Set<T>().Remove(entity);
}
public virtual void Edit(T entity) {
_entities.Entry(entity).State = System.Data.EntityState.Modified;
}
public virtual void Save() {
_entities.SaveChanges();
}
}
Now I want to create class for each of my database tables to save the data.
Here is the code for one of my database tables:
public class AmountDLL : GenericRepository<HMSEntities, Tbl_Amount>
{
//:Base<Tbl_Amount>
public override void Add(Tbl_Amount entity)
{
base.Add(entity);
}
}
At last I have tried to add data through front end on button click
protected void btnsave_Click(object sender, EventArgs e)
{
AmountDLL amtdll = new AmountDLL();
Tbl_Amount tblamt = new Tbl_Amount();
tblamt.Amt_Type = txt_amt_type.Text;
tblamt.UserId = User.Identity.GetUserId();
if (CheckBox1.Checked == true)
{
tblamt.IsActive = true;
}
else
{
tblamt.IsActive = false;
}
amtdll.Add(tblamt);
}
When I run the application, it worked fine, but it did not save the data in the table.
Please check and suggest any changes
In Entity Framework for every entity to save the data either it's insert, update or delete, we call the SaveChanges() on instance of that entity.
In your case you need to call the Save() method for persisting to database which you have defined in your repository class for that which abstracts the SaveChanges() call to your respective Entity type:
amtdll.Add(tblamt);
amtdll.Save(); // this needs to be called.
public interface IRepository<T> : IDisposable
{
void Add(T newEntity);
void Delete(T entity);
T Find(int id);
IQueryable<T> FindAll();
int Commit();
}
public class SqlRepository<T> : IRepository<T> where T : class
{
DbContext context;
DbSet<T> set;
public SqlRepository(DbContext context)
{
this.context = context;
this.set = context.Set<T>();
}
public void Add(T newEntity)
{
this.set.Add(newEntity);
}
public void Delete(T entity)
{
}
public T Find(int id)
{
throw new Exception("todo");
}
public IQueryable<T> FindAll()
{
return this.set;
}
public int Commit()
{
return this.context.SaveChanges();
}
public void Dispose()
{
this.context.Dispose();
}
}
using (IRepository<Contact> e = new SqlRepository<Contact>(new AppointmentReminderDb()))
{
e.Add(new Contact() { Active = true });
e.Add(new Contact() { Active = true });
e.Commit();
var count = await e.FindAll().Count(); // do not get Count property
}
In the above line of code, I don't understand why I am not getting Count property. Instead I get CountAsynch. I really want to simply get Count property.
My IQueryable for FindAll is correctly defined in the interface and in the class method.
You may have forgotten to include the right namespace.
The method you're seeing in IntelliSense is named QueryableExtensions.CountAsync<TSource> defined in the System.Data.Entity namespace, which returns Task<int> and, as such, should be awaited.
The method (not property) you're looking for is named Queryable.Count<T>() and is defined in the System.Linq namespace. It returns an int and should not be awaited.
If the operation involves IO, which it probably does, you want to use CountAsync.
I want to create a common database abstraction in order to expose the same interface without worrying about the type of the DbContext that the database manage.
Here there is an example in order to explain well the concept:
public interface IDatabase<T> where T : DbContext {
void Add<T>(T entity);
void Remove<T>(T entity);
void SaveChanges();
}
The implementation can be:
public MyDatabase<T> : IDatabase<T> where T : MyContext {
public T Context { get; private set; }
//singleton contructor ...
public void Add<TC>(TC entity) {
Context.Set<TC>().Add(entity);
}
public void Remove<TC>(TC entity) {
Context.Set<TC>().Add(entity);
}
public void SaveChanges {
Context.SaveChanges();
}
}
The goals of this design are different: expose the same interface in order to decouple logic from database, change quickly the database (context), create one time the context and reuse during all the application lifetime (lock mechanism are required).
The problem is that the interface hides all the types of the sets in the context.
Context.Set<TC>().Add(entity); //this line don't compile
I'm not sure that this design is the best practise. How can I implement a design that offers these features?
Why you does not use the standard pattern for example Repository pattern you can also combine it with UnitOfWork.
You make it complicated for your self, just check this.
public interface IMyClassRepository : IDisposable
{
IQueryable<MyClass> All { get; }
IQueryable<MyClass> AllIncluding(params Expression<Func<MyClass, object>>[] includeProperties);
MyClass Find(int id);
void InsertOrUpdate(MyClass myClass);
void Delete(int id);
void Save();
}
public class MyClassRepository : IMyClassRepository
{
DBContext context = new DBContext();
public IQueryable<MyClass> All
{
get { return context.Employees; }
}
public IQueryable<MyClass> AllIncluding(params Expression<Func<MyClass, object>>[] includeProperties)
{
IQueryable<MyClass> query = context.MyClasses;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public MyClass Find(int id)
{
return context.MyClasses.Find(id);
}
public void InsertOrUpdate(MyClass myClass)
{
if (myClass.Id == default(int))
{
// New entity
context.MyClasses.Add(myClass);
}
else
{
// Existing entity
context.Entry(myClass).State = EntityState.Modified;
}
}
public void Delete(int id)
{
var employee = context.Employees.Find(id);
context.Employees.Remove(employee);
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public class MyClass
{
}
I am new to mongodb and I am working on mvc4 web application for a new project.
I want to use repository pattern that will talk to a mongodb context for database level communications.
Simple interface that I have used with Entity Framework 4.0 is following. The find members are the problematic area for me. I don't have a clue how to proceed with them with mongodb context.
public interface IRepository<T> where T : class
{
void Add(T entity);
void Remove(T entity);
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
//IQueryable<T> FindAll();
}
I have a very simple model that is called Hero its drive from ImongoEntity which provides a member called accessId.
public class Hero : MongoDB.Kennedy.IMongoEntity
{
public ObjectId _id { get; set; }
public string Name { get; set; }
public string Alias { get; set; }
public string _accessId { get; set;}
}
Context class is very simple you can see the collection of Heros exposted as IQueryable property.
public class MongoDataConetext: MongoDB.Kennedy.ConcurrentDataContext
{
public MongoDataConetext(string databaseName, string serverName="localhost") : base(databaseName, serverName)
{
}
public IQueryable<Hero> Heros {
get {
return base.GetCollection<Hero>().AsQueryable();
}
}
}
Now in my repository most simple methods are add and remove they successfully talk to mongodb context and get entities added or deleted from mongodb. Find method however gives me compiler level errors. I need help for my find and find all method. I am using genrics because I need my repositry class for enties like hero, solution, project, user and category.
public class Repository<T> : IRepository<T> where T : class, IMongoEntity
{
private readonly MongoDataConetext _ctx;
public Repository(MongoDataConetext ctx)
{
_ctx = ctx;
}
public void Add(T entity)
{
_ctx.Save(entity);
}
public void Remove(T entity)
{
_ctx.Delete(entity);
}
public IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
_ctx.Heros.Where(predicate);
//throw new NotImplementedException();
}
//public IQueryable<T> FindAll()
//{
// throw new NotImplementedException();
//}
}
If you are interested in an implementation similar to Rob Connery's and NBlog storage code but using the mongodb csharp driver 2.0 (that is asynchronous), you can look at:
https://github.com/alexandre-spieser/mongodb-generic-repository
You can then write a custom repository inheriting from BaseMongoRepository.
public interface ITestRepository : IBaseMongoRepository
{
void DropTestCollection<TDocument>();
void DropTestCollection<TDocument>(string partitionKey);
}
public class TestRepository : BaseMongoRepository, ITestRepository
{
public TestRepository(string connectionString, string databaseName) : base(connectionString, databaseName)
{
}
public void DropTestCollection<TDocument>()
{
MongoDbContext.DropCollection<TDocument>();
}
public void DropTestCollection<TDocument>(string partitionKey)
{
MongoDbContext.DropCollection<TDocument>(partitionKey);
}
}
Update: It is now available as its own nuget package:
Install-Package MongoDbGenericRepository
It looks like you're trying to use LINQ against your collections. That's perfect. You can do this much easier if you just expose an IQueryable property rather than write a Find() method.
Here's an example from you sample above:
public class HeroRepository : IRepository<Heros> where T : class, IMongoEntity
{
// ...
public IQueryable<Heros> Heros
{
get
{
return _ctx.GetCollection<Heros>().AsQueryable();
// Careful there, doing this from memory, may be a little off...
}
}
}
Of course, then when you consume this class, just do:
var r = new HeroRepository();
var heros = r.Heros.Where(r => r.SuperPowerLevel > 20);
Generic
public class MongoDatabase<T> : IDatabase<T> where T : class, new()
{
private static string connectionString = "connectionString";
private static IMongoClient server = new MongoClient(connectionString);
private string collectionName;
private IMongoDatabase db;
protected IMongoCollection<T> Collection
{
get
{
return db.GetCollection<T>(collectionName);
}
set
{
Collection = value;
}
}
public MongoDatabase(string collection)
{
collectionName = collection;
db = server.GetDatabase(MongoUrl.Create(connectionString).DatabaseName);
}
public IMongoQueryable<T> Query
{
get
{
return Collection.AsQueryable<T>();
}
set
{
Query = value;
}
}
public T GetOne(Expression<Func<T, bool>> expression)
{
return Collection.Find(expression).SingleOrDefault();
}
public T FindOneAndUpdate(Expression<Func<T, bool>> expression, UpdateDefinition<T> update, FindOneAndUpdateOptions<T> option)
{
return Collection.FindOneAndUpdate(expression, update, option);
}
public void UpdateOne(Expression<Func<T, bool>> expression, UpdateDefinition<T> update)
{
Collection.UpdateOne(expression, update);
}
public void DeleteOne(Expression<Func<T, bool>> expression)
{
Collection.DeleteOne(expression);
}
public void InsertMany(IEnumerable<T> items)
{
Collection.InsertMany(items);
}
public void InsertOne(T item)
{
Collection.InsertOne(item);
}
}
İnterface
public interface IDatabase<T> where T : class, new()
{
IMongoQueryable<T> Query { get; set; }
T GetOne(Expression<Func<T, bool>> expression);
T FindOneAndUpdate(Expression<Func<T, bool>> expression, UpdateDefinition<T> update, FindOneAndUpdateOptions<T> option);
void UpdateOne(Expression<Func<T, bool>> expression, UpdateDefinition<T> update);
void DeleteOne(Expression<Func<T, bool>> expression);
void InsertMany(IEnumerable<T> items);
void InsertOne(T item);
}
I know that It's a quite old post, but I would like to share with you the MongoRepository project implemented at Github or download as a NuGet package
Note: One of the problem that I had trying to implement the MongoDB Repository has been the different behaviour depending on the MongoDB driver version or wich is more or less the same, the .NET Framework. The MongoRepository project (in the link above) has solved this problem whith different code versions for .net 3.5, 4.0 and 4.5 frameworks that use different version of MongoDB driver (check MongoDB driver compatibility), wich has been very helpful.
I have the following Repository Pattern. Requirement is to “Find All accounts whose owner’s name is Lijo”. So, I need to write a FindAll function. How to write this function?
Constraints are:
1) The client “BankAccountService” should not use classes from 'DBML_Project'.
2) We should NOT use GetAll method to retireve complete list of accounts and then do a filter.
Note: I confronted this problem while working on the question Polymorphism: Is ORM entity a Domain Entity or Data Entity?
CODE
namespace ApplicationService_Bank
{
public class BankAccountService
{
RepositoryLayer.ILijosBankRepository accountRepository = new RepositoryLayer.LijosSimpleBankRepository();
public void FreezeAllAccountsForUser(string userName)
{
//Should not use assembly 'DBML_Project'.
IEnumerable<DomainEntitiesForBank.IBankAccount> accountsForUserWithNameLIJO = null;
//accountsForUserWithNameLIJO = accountRepository.FindAll(p => p.BankUser.Name == "Lijo");
}
}
}
namespace RepositoryLayer
{
public interface ILijosBankRepository
{
List<DomainEntitiesForBank.IBankAccount> GetAll();
IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate);
void SubmitChanges();
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
private IBankAccountFactory bankFactory = new MySimpleBankAccountFactory();
public System.Data.Linq.DataContext Context
{
get;
set;
}
public virtual List<DomainEntitiesForBank.IBankAccount> GetAll()
{
List<DBML_Project.BankAccount> allItems = Context.GetTable<DBML_Project.BankAccount>().ToList();
List<DomainEntitiesForBank.IBankAccount> bankAccounts = new List<DomainEntitiesForBank.IBankAccount>();
foreach (DBML_Project.BankAccount acc in allItems)
{
DomainEntitiesForBank.IBankAccount theAccount = bankFactory.CreateAccount(acc.AccountType, acc.BankAccountID, acc.Status, acc.OpenedDate, acc.AccountOwnerID);
bankAccounts.Add(theAccount);
}
return bankAccounts;
}
public IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate)
{
//Where
var results = Context.GetTable<DBML_Project.BankAccount>().Where(predicate);
return results;
}
public virtual void SubmitChanges()
{
Context.SubmitChanges();
}
}
}
READING:
Returning IEnumerable<T> vs. IQueryable<T>
how to design Repository pattern to be easy switch to another ORM later?
A simple approach is to just build the query by hand:
public class SearchCriteria
{
public string Name { get; set; }
// ...more
}
public IEnumerable<Entity> FindAll(SearchCriteria criteria)
{
IQueryable<Entity> entities = _datasource.Entities; // replace with your L2S equivalent
if (criteria.Name != null)
entities = entities.Where(e => e.Name == criteria.Name);
// ...more
return entities;
}
If you don't want to return the generated objects directly, map to something else before you return:
return Map(entities); // IEnumerable<CustomObject> Map(IEnumerable<Entity> entities)