简体   繁体   中英

UnitofWork + DependencyResolver will raise an exception when calling .Save() “The relationship between the two objects cannot be defined”

I am working on an asp.net mvc 5.2 web application + Entity framework 6. and i have defined 2 repositories for two entities; SecurityRole and Staff, then i defined a unit of work between them as follow:-

public class UnitOfWork : IDisposable
    {
        private SkillManagementEntities context = new SkillManagementEntities();
        private SkillRepository skillRepository;
        private StaffRepository staffRepository;
        private SecurityRoleRepository securityroleRepository;
        private CustomerRepository customerRepository;
        private SkillVersionHistoryRepository SVH;
        private LinkToKBRepository linkToKBRepository;
        public SkillRepository SkillRepository
        {
            get
            {

                if (this.skillRepository == null)
                {
                    this.skillRepository = new SkillRepository(context);
                }
                return skillRepository;
            }
        }

        public StaffRepository StaffRepository
        {
            get
            {

                if (this.staffRepository == null)
                {
                    this.staffRepository = new StaffRepository(context);
                }
                return staffRepository;
            }
        }

        public SecurityRoleRepository SecurityRoleRepository
        {
            get
            {

                if (this.securityroleRepository == null)
                {
                    this.securityroleRepository = new SecurityRoleRepository(context);
                }
                return securityroleRepository;
            }
        }

        public async Task Save()
        {
            await context.SaveChangesAsync();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

now inside the SecurityRole controller i have the following action method , to assign Staffs to security role:-

public class SecurityRoleController : Controller
    {

    UnitOfWork uniteofwork = new UnitOfWork(); 
[HttpPost]
        [ValidateAntiForgeryToken]

        public async Task<ActionResult> AssignStaffsToSR(int? id , int[] selectedStaffsids)
        {


            var dbsecurityrole = new SecurityRole();
            try
            {

                dbsecurityrole = await uniteofwork.SecurityRoleRepository.FindSecurityRole(id.Value,sr=>sr.Staffs);
              uniteofwork.SecurityRoleRepository.UpdateSecurityRoleUsers(selectedStaffsids, dbsecurityrole);
              await uniteofwork.Save();
                TempData["message"] = string.Format("{0} User/s have been Assigned", String.Empty);
                if (Request.IsAjaxRequest())
                {
                    return Json(new { ISsuccess = true });
                }

                return RedirectToAction("Details", new { id = id });


            }
            catch (Exception e)
            {
                ModelState.AddModelError(string.Empty, "Error occured");
            }



                 return View(await uniteofwork.SecurityRoleRepository.populateAssignStaff(dbsecurityrole)); 
            }

which calls the following repository method:-

public class SecurityRoleRepository :  ISecurityRoleRepository , IDisposable
        {
         private SkillManagementEntities context;
         private IStaffRepository staffrepo = (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository));
         public SecurityRoleRepository(SkillManagementEntities context)
            {
                this.context = context;
            }
public void UpdateSecurityRoleUsers(int[] selectedUsers, SecurityRole securityRole)
              {
                  var dbSecurityRolestaffs = securityRole.Staffs.ToList();
                  var activestaffs = staffrepo.GetActiveStaff().ToList();

                  foreach (var s in activestaffs)
                  {

                      if (selectedUsers.Contains(s.StaffID))
                      {
                          if (!dbSecurityRolestaffs.Any(a => a.StaffID == s.StaffID))
                          {

                              securityRole.Staffs.Add(s);
                          }
                      }
                      else
                      {
                          if (dbSecurityRolestaffs.Any(a => a.StaffID == s.StaffID))
                          {
                              securityRole.Staffs.Remove(s);
                          }



                      }
                  }

              }

and i have defined the following dependency resolver between the repositories:-

public class YourDependencyResolverClass : IDependencyResolver
{
    private IKernel kernel;

    public YourDependencyResolverClass()
    {
        kernel = new StandardKernel();
        AddBindings();
    }

    public object GetService(Type serviceType)
    {
        return kernel.TryGet(serviceType);
    }
    public IEnumerable<object> GetServices(Type serviceType)
    {
        return kernel.GetAll(serviceType);
    }


    private void AddBindings()
    {
        kernel.Bind<ISkillRepository>().To<SkillRepository>();
        kernel.Bind<IStaffRepository>().To<StaffRepository>();
        kernel.Bind<ISecurityRoleRepository>().To<SecurityRoleRepository>();
        kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
        kernel.Bind<ISkillVersionHistoryRepository>().To<SkillVersionHistoryRepository>();
     }

but currently when i call the await uniteofwork.Save(); inside my action method i got the following exception:-

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

although i am using a UnitofWork class which should pass the same objectcontext between the repositories and entities ??

UnitOfWork uniteofwork = new UnitOfWork(); -> Always create a connection, you should open connection when you need, dont use like that

using(UnitOfWork unitOfWork = new UnitOfWork()){
    unitOfWork.YourRepository.DoStuff();
    unitOfWork.Save();
}

Maybe your problem here: (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository)); This will get StaffRepository for you and the context is different.

You can try to fix like this, but i'm not recommend this way because code is not good.

 private IStaffRepository staffrepo;
 public SecurityRoleRepository(SkillManagementEntities context)
 {
      this.context = context;
      staffrepo = new StaffRepository(context);
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM