[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1710
  • Last Modified:

Updating object in different objectcontext in entity framework

I have a .Net 3.5 Windows application written in c# using the entity framework and I am struggling badly with updating.  In the DB I have Job and Status tables where there is a FK from Job.StatusID to Status.ID.  In my appplication I have two corresponding entities and I am fine with retrieving them and adding new.

I am creating and disposing objectcontexts as needed.  To retrieve a Job I have a Get() method as shown in the first code snippet.  This works great.  The problem is when I want to update a reference.  I can't go Job.Status = newStatus where new status is from a similar Get() method as they are from different contexts so it blows up.  Also, I can't have a Job.SetStatus(Status newStatus) as that will simply crack open new contexts and the original Job object won't be updated.

I am desperate to get these basics working!


public static Job Get(string name)
        {
            Job res;
            using (var db = new CanDoAndonEntities())
            {
                res = (from j in db.Job
                       where j.Name == name
                       select j).FirstOrDefault();
                res.JobStatusReference.Load();
            }
            return res;
        }

Open in new window

0
canuckconsulting
Asked:
canuckconsulting
  • 9
  • 6
1 Solution
 
Fernando SotoRetiredCommented:
Hi canuckconsulting;

Not sure what you are really trying to do but if you are taking the results of the above method and trying to add it to another ObjectContext that will not work because you can not add an object to one context that belongs to another context. The way to do that is to Detach the object and then Attach the object to the new ObjectContext. See code snippet.

Fernando
public static Job Get(string name)
{
    Job res;
    using (var db = new CanDoAndonEntities())
    {
        res = (from j in db.Job
               where j.Name == name
               select j).FirstOrDefault();
        res.JobStatusReference.Load();
        // Detach the object res and all its structures from the ObjectContext
        db.Detach(res);
    }
    return res;
}

....

Then when you are ready to add it to a different ObjectContext do something like this.
using (var db = new CanDoAndonEntities())
{
    db.Attach(The Job object returned from the method);
    ...
}

Open in new window

0
 
canuckconsultingAuthor Commented:
When I do try this I get an error "An entity object cannot be referenced by multiple instances of IEntityChangeTracker".  
0
 
canuckconsultingAuthor Commented:
It would help if I read your answer properly.  I just noticed your detached line...testing now.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
canuckconsultingAuthor Commented:
Ok. it is not working.  I had simplified my example a bit the job is actually a reference off an other entity.  The Job entity is a FK from a Session entity.  So I first create a sesison passing in a Job as shown in the Session.New() method below.   Using the result I then call Job.SetMethod() as described in the second method shown in the snippet.  Do those look right?

 Finally here is an example of how I would use it:

            int staff = 10;
            Session session = Session.New(job, staff);
            var active = Status.Active(); //returns a Status entity
            _session.Job.SetStatus(active);

When the code hits the last line I get a "Object reference not set to an instance of an object." error.  Sure enough Job is null!  Why did detaching this kill my JobReference?  How can I work around this?
//Session.New() method
        public static Session New(Job job, int operators)
        {
            var res = new Session
                          {
                              CompletedItems = 0,
                              StartDate = DateTime.Now,
                              Operators = operators
                          };

            using (var db = new CanDoAndonEntities())
            {
                res.Job = (from j in db.Job
                           where j.ID == job.ID
                           select j).FirstOrDefault();

                db.AddToSession(res);
                db.SaveChanges();
                res.JobReference.Load();
                db.Detach(res); //NEW CODE HERE
            }
            return res;
        }

// Job.SetStatus method
        public void SetStatus(Status status)
        {
            using (var db = new CanDoAndonEntities())
            {
                db.Attach(this);  //NEW CODE HERE
                db.Attach(status); //NEW CODE HERE
                this.Status = status;
            }
        }

Open in new window

0
 
Fernando SotoRetiredCommented:
Hi canuckconsulting;

Is this object "active" been detach from the ObjectContext it came from?

var active = Status.Active(); //returns a Status entity

This statement, _session.Job.SetStatus(active);, takes a status object as a parameter and execute the method SetStatus. SetStatus creates a new ObjectContext CanDoAndonEntities and attaches two entity types as seen here:

    using (var db = new CanDoAndonEntities())
    {
        db.Attach(this);  //NEW CODE HERE
        db.Attach(status); //NEW CODE HERE
        this.Status = status;
    }
   
The only thing this code is doing is setting the current object to status. The two Attach really do nothing because the ObjectContext is never updated to the database.

The ObjectContext is just a in memory copy of the records retrieved from the database in a query. So if the records in the ObjectContext are not modified, deleted or added as new and the changes are not submiutted, nothing happens. So in the above using block you need to do a SaveChanges call to update the database.

Fernando
0
 
canuckconsultingAuthor Commented:
Hi Fernando,

Yes, I called detach in the Status entity.  

When I step through the Session.New() method and get to the detach line it nulls Session.Job as well as  any other FK references.  The entity then becomes pretty unusuable.
0
 
Fernando SotoRetiredCommented:
Hi canuckconsulting;

Where is the Job object that is attached to the Session object created/retrieved from? For example if I create a Session and I also need to fill in some of the fields of a Job object I will need to create a new Job and assign it to the Job field of the Session.

Session session = new  Session();
...
Job job = new Job();
...
session.Job = job;

Fernando
0
 
canuckconsultingAuthor Commented:
The Job object will already exist in the DB so it is simply retrieved in the Session.New method.  See line 13 in my code sample.
0
 
Fernando SotoRetiredCommented:
What does the method AddToSession look like, line 17 shown below?

db.AddToSession(res);
0
 
canuckconsultingAuthor Commented:
It is generated by the entity frame work.  From the file CanDoModel.Designer.cs:

        public void AddToSession(Session session)
        {
            base.AddObject("Session", session);
        }
0
 
Fernando SotoRetiredCommented:
Sorry I am getting a little confused on this end. Lets try it this way.

On what line of the code is the program crashing on?
What are the values of the objects on that line?
What is the exact error message that is returned?

How big is this project at this time?
0
 
canuckconsultingAuthor Commented:
If I was to run the following:

            int staff = 10;
            Session session = Session.New(job, staff);
            var active = Status.Active(); //returns a Status entity
            _session.Job.SetStatus(active);  //Crash here - _session.Job is null.

The crashes when trying to reference Job and the error is " "Object reference not set to an instance of an object."   Sure enough _session.Job is null as is every other FK reference.  The field was made null as soon as I called detach in the session.New() menthod.

The project is about a dozen classes in size with six of those being entitiy related.   Note sure how to express how big it is!
0
 
Fernando SotoRetiredCommented:
The reason for the size of the project is that if you can posty it with a test DB I could have a better look at it. Is that possible?
0
 
canuckconsultingAuthor Commented:
Thank you for your offer and I may be able to that but not now.  this needs to be working for tomorrow morning so I have decided to either use a shared context or rip it out and go back to ado.net.  

I am disapointed that such a simple task has proven so difficult and am regretting not putting the time into nHibernate or some other ORM solution.  I will come back to this after I make my deadline.  Thank you again for your help.
0
 
canuckconsultingAuthor Commented:
I am closing this ticket as I am moving to .Net 4.0 and things will change dramatically.  While I was not able to get this to work I am sure it was down to a niggle in my environment.  Thank you for your help!
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

  • 9
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now