Pregunta

I have an object A that has another object B inside. I am loading the using EntityFramework and modifying the object B but when I set the State to EntityState.Modified I have this error{"An entity object cannot be referenced by multiple instances of IEntityChangeTracker."}

This are my objects

public class Patient : IEntity, IObjectWithState
{
    public virtual int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsMobileActived { get; set; }

    public virtual MobilePatient MobilePatient { get; set; }

    [NotMapped]
    public State State { get; set; }
}

public class MobilePatient : IObjectWithState
{
    public virtual int Id { get; set; }
    public virtual int PatientPin { get; set; }
    public virtual string SecurityAnswer { get; set; }
    public virtual bool IsPinRemembered { get; set; }
    public virtual PhysiologicalData PhysiologicalData { get; set; }

    [NotMapped]
    public State State { get; set; }
}

I have a repository and a unit of work and bascally using it I am loading the Patient object in this way.

...   Patient patient = context.Patients.Find(id); ...

Then with the patient I am updating the MobilePatient

... patient.MobilePatient = NEWmobilePatient; ...

and then updating it with

PatientContext patientContext = (PatientContext)context;
patientContext.Entry(patient).State = EntityState.Modified;

My context only has the Patient dbset

public class PatientContext:BaseContext<PatientContext>, IPatientContext
{
    public IDbSet<Patient> Patients { get; set; }

    public void SetModified(object entity)
    {
       Entry(entity).State = EntityState.Modified;
    }

    public void SetAdd(object entity)
    {
        Entry(entity).State = EntityState.Added;
    }
}

So I dont know what I am missing to update. When I am loading the Patient I am using the default lazy-load but how I have data in MobilePatient I am getting that object too.

Something that I think could be a good information is that I am using unit of work and repository and my application a disconnect application.

This my repository:

public class PatientRepository : IRepository<Patient>
    {
        private IPatientContext context=new PatientContext();

        public PatientRepository(PatientContext context)
        {
            this.context = context;
        }

        public void Add(Patient patient)
        {
             context.SetAdd(patient);
        }

        public void Update(Patient patient)
        {
           context.SetModified(patient);
        }

        public void Delete(Patient entity)
        {
            throw new NotImplementedException();
        }

        public Patient FindById(int id)
        {

            Patient patient = context.Patients.Find(id);
            return patient;
        }

        public IQueryable<Patient> Find(Expression<Func<Patient, bool>> predicate)
        {
           PatientContext patientContext = (PatientContext)context;
           return patientContext.Set<Patient>().Where(predicate).AsQueryable<Patient>();
        }

        public IQueryable<Patient> FindAll()
        {
            return context.Patients;
        }
    }

I an this how I am using it in my services :

Patient patient = new Patient();
using (IPatientLoaderService patientLoaderService = AppManager.Instance.Database.CreatePatientLoaderService())
    {
       patient = patientLoaderService.LoadPatientById(patientId);
    }


patient.MobilePatient =New_mobilePatient;
patient.State = State.Modified;
patient.Age = 40;
using (IPatientUpdaterService patientUpdaterService = AppManager.Instance.Database.CreatePatientUpdaterService())
        {
            patientUpdaterService.UpdatePatient(patient);
        }

In my services I use the unit of work and the repositories this is one of my services used in the code:

public class EntityFrameworkPatientUpdaterService: IPatientUpdaterService
    {
        private   PatientRepository patientsRepository;
        private   EntityFrameworkUnitOfWork<PatientContext> unitOfWork;
        public EntityFrameworkPatientUpdaterService()
        {
            unitOfWork = new EntityFrameworkUnitOfWork<PatientContext>();
            PatientContext patientContent = new PatientContext();
            patientsRepository = new PatientRepository(patientContent);
        }

        public void UpdatePatient(Patient patient)
        {   try
            {
                patientsRepository.Update(patient);
                unitOfWork.Commit();
            }
            catch (Exception e)
            {
                //TODO: Log the error and evoid to throw another exception-DOR
                unitOfWork.Dispose();
                throw new Exception("Error on EntityFrameworkPatientUpdaterService.UpdatePatient. " +
                                     e.Message);
            }
            finally
            {
                unitOfWork.Dispose();
                unitOfWork = new EntityFrameworkUnitOfWork<PatientContext>();
                PatientContext patientContent = new PatientContext();
                patientsRepository = new PatientRepository(patientContent);
            }
        }

        public void Dispose()
        {
            unitOfWork.Dispose();
        }
}

Thank you for read this post

I am going to be adding more detail on how I am currently using my service. I think the problem is that I am trying to use tghe Onion Architecture and I am missing something.

public class PatientContext:BaseContext<PatientContext>, IPatientContext
    {
        public IDbSet<Patient> Patients { get; set; }
        public void SetModified(object entity)
        {
           Entry(entity).State = EntityState.Modified;
        }

    }

    public class PatientRepository : IRepository<Patient>
    {
        private readonly IPatientContext context;

        public PatientRepository(PatientContext context)
        {
            this.context = context;
        }


        public void Update(Patient patient)
        {
          context.SetModified(_patient);

        }

        public Patient FindById(int id)
        {

            Patient patient = context.Patients.Find(id);
            return patient;
        }
    }

    public class EntityFrameworkPatientUpdaterService
    {
        private   PatientRepository patientsRepository;
        private   EntityFrameworkUnitOfWork<PatientContext> unitOfWork;
        public EntityFrameworkPatientUpdaterService()
        {
            unitOfWork = new EntityFrameworkUnitOfWork<PatientContext>();
            PatientContext patientContent = new PatientContext();
            patientsRepository = new PatientRepository(patientContent);
        }

        public void UpdatePatient(Patient patient)
        {   try
            {
                patientsRepository.Update(patient);
                unitOfWork.Commit();
            }
            catch (Exception e)
            {
                //TODO: Log the error and evoid to throw another exception-DOR
                unitOfWork.Dispose();
                throw new Exception("Error on EntityFrameworkPatientUpdaterService.UpdatePatient. " +
                                     e.Message);
            }
            finally
            {
                unitOfWork.Dispose();
            }
        }

        public void Dispose()
        {
            unitOfWork.Dispose();
        }
    }

    //GEtting the patient and dispose everything,
     Patient patient = new Patient();
            using (IPatientLoaderService patientLoaderService = AppManager.Instance.Database.CreatePatientLoaderService())
            {
                patient = patientLoaderService.LoadPatientById(patientId);
            }
    //THEN Calling my services to update
     using (IPatientUpdaterService patientUpdaterService = AppManager.Instance.Database.CreatePatientUpdaterService())
            {
                patientUpdaterService.UpdatePatient(patient);
            }
¿Fue útil?

Solución

If I interpret the exception message correctly, it means that you have two contexts, and both want the entry of your entity. This is not possible, only one context at the time can deal with a data row at a time.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top