FosterZ
FosterZ

Reputation: 3911

Entity framework 4.1 An entity object cannot be referenced by multiple instances of IEntityChangeTracker

i have read many of the answer related to this error and i also got some few answers which are close to my question but im not able to track what i'm doin' wrong here

i have a class generic repository

public abstract class GenericRepository<TC,T>:IGenericRepository<T> where T:class where TC:ObjectContext , new()
{
    private TC _entities = new TC();
    public TC Context
    {

        get { return _entities; }
        set { _entities = value; }
    }
    public virtual IQueryable<T> GetAll()
    {

        IQueryable<T> query = _entities.CreateObjectSet<T>();
        return query;
    }
    public virtual void Add(T entity)
    {
        _entities.CreateObjectSet<T>().AddObject(entity);
    }
    // save,update,insert etc etc
}

and my repository class is

public class MenuRepository:GenericRepository<mbsEntities,menu>,IMenu
{
    public menu GetMenu(int id)
    {
        return GetAll().FirstOrDefault(x => x.menu_id == id);
    }
    public bool CreateMenu(string menuName, int menuLevel, string menuUrl, int menuParent,int menuPosition,int roleId)
    {
        if(!Profile.IsInRole(Enums.Enumerations.Roles.Admin))
            return false;
        var menu = new menu()
                       {
                           menu_name = menuName,
                           menu_level=menuLevel,
                           menu_url = menuUrl,
                           menu_parent = menuParent,
                           menu_position = menuPosition,

                       };
        var roleRepository = new RoleRepository();
        var role = roleRepository.GetAll().FirstOrDefault(x => x.id == roleId);
        menu.traffic_role.Add(role);
        try
        {
            Add(menu);      // here im getting error “An entity object cannot be referenced by multiple instances of IEntityChangeTracker”
            Save();
        }
        catch (Exception)
        {
            return false;
        }
        return true;
    }
}

am i goin' in a wrong way ??

Upvotes: 0

Views: 693

Answers (1)

Eranga
Eranga

Reputation: 32437

Your 'MenuRepository' and RoleRepository repository use different contexts. Set the context of the RoleRepository to use the MenuRepository's context before querying.

public class MenuRepository:GenericRepository<mbsEntities,menu>,IMenu
{
    public menu GetMenu(int id)
    {
        return GetAll().FirstOrDefault(x => x.menu_id == id);
    }
    public bool CreateMenu(string menuName, int menuLevel, string menuUrl, int menuParent,int menuPosition,int roleId)
    {
        if(!Profile.IsInRole(Enums.Enumerations.Roles.Admin))
            return false;
        var menu = new menu()
                       {
                           menu_name = menuName,
                           menu_level=menuLevel,
                           menu_url = menuUrl,
                           menu_parent = menuParent,
                           menu_position = menuPosition,

                       };
        var roleRepository = new RoleRepository();

        roleRepository.Context = Context;

        var role = roleRepository.GetAll().FirstOrDefault(x => x.id == roleId);
        menu.traffic_role.Add(role);
        try
        {
            Add(menu);      // here im getting error “An entity object cannot be referenced by multiple instances of IEntityChangeTracker”
            Save();
        }
        catch (Exception)
        {
            return false;
        }
        return true;
    }
}

The design suffers from leaky abstraction. Use constructor injection for repositories to inject the context. You can prevent accidentally creating multiple contexts to some extent. Use an Dependency Injection framework and make your dependencies explicit without instantiating them inside the method.

public abstract class GenericRepository<TC,T>:IGenericRepository<T> where T:class where TC:ObjectContext , new()
{
    protected GenericRepository(TC context)
    {
       Context = context;
    }

    public TC Context
    {
        get; protected set;
    }

}

Upvotes: 1

Related Questions