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);
}