Milos Zivkovic
Milos Zivkovic

Reputation: 117

EntityFramework Repository Pattern

I've been having a problem with my code. I've started learning Entityframework, as a resorce i've used Microsoft Virtual Academy website, they have a short intro for Entity Framework and asp.net. They have created this repository generic class that takes poco classes.

public class Repository<T> where T : class
{
    private BlogDataContext context = null;
    protected DbSet<T> DbSet { get; set; }

    public Repository()
    {
        this.context = new BlogDataContext();
        DbSet = context.Set<T>();
    }

    public List<T> getAll()
    {
        return DbSet.ToList();
    }

    public T Get(int id)
    {
        return DbSet.Find(id);
    }

    public void Add(T entity)
    {
        DbSet.Add(entity);
    }

    public void Update(T entity)
    {
        context.Entry<T>(entity).State = EntityState.Modified;
    }

    public void Delete(int id)
    {
        DbSet.Remove(DbSet.Find(id));
    }

    public void SaveChanges()
    {
        context.SaveChanges();
    }
}

Problem appears when you need to edit data in database using ASP.NET Controls, Up until now I've manually bound data to controls and updated by finding the data with Get(int Id) and then updating. Recently I found out that the process can be automated with ObjectDataSource control but update method casts an error

Attaching an entity of type 'CarDealership.DataLayer.UsersExtended' failed because another entity of the same type already has the same primary key value.

UsersExtended is a poco class.

Upvotes: 4

Views: 522

Answers (1)

ocuenca
ocuenca

Reputation: 39386

Don't use Get method because is going to attach the resulted entity to your context, and when you pass a disconnected POCO entity to your Update method with the same Id, EF will throw that exception.

If your entities inherit from a common class where you define the PK property of all your entities, eg:

public class Entity
{
   public int Id{get;set;}
}

To avoid that issue you can add the following method to your repository to check if the row exist or not in your DB:

public class Repository<T> where T : Entity
{
     //...
     public bool Exist(int id)
    {
      return DbSet.Exist(e=>e.Id==id);
    }
}

And if you don't have that design you can do the following in your business layer to check the same:

var repository= new Repository<UsersExtended>();
bool exist= repository.GetAll().Exist(e=>e.Id==id);
if(exist)
{ 
   repository.Update(yourEntity)
}

Another important thing, never call ToList extension method from a DbSet, that's going to load all your table to memory. Change it to something like this:

public IQueryable<T> GetAll()
{
    return DbSet;
}

Always try to consult your data in your BL, and at the end of your query call ToList extension method to load only the desired entities.

Upvotes: 3

Related Questions