0

I have an entity "Question" that are used by both entities "QuestionSet" and "Survey". The logic is, create a set of questions, but when adding questions to a survey, create a clone so that editing question in a questionset will not change the question in the survey. However since there is explicit update functionality the clone (in survey) needs to know it's origin (question in questionset).

I solved this by added a

public virtual Question CreatedFrom { get; set; }

in Question. However when I now do as follows in my controller

oldQ = _questionRepository.GetById(qTransfer.Id);
q = new Question(oldQ);
q.CreatedFrom = oldQ;
q.Id = 0;

where the copy constructor of Q makes a complete copy of the question values (creating the clone).

And finally this in my repo

if (item.Id == 0)
{
    Add(item); //this calls Add on dbset
}
ActiveContext.SaveChanges();

I get this error: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

If I comment away q.CreatedFrom = oldQ; then i no longer get the error.

What I want is simply to reference the questions parent when i create a clone. I still want the original question to operate independently. I could of course simply replace CreatedFrom with CreatedFromId, but i thought it would be nice with a direct reference.

Update

Here is my cloning code. While cloning I copy the reference for CreatedFrom however that should be null in the object being cloned.

    public Question(Question q)
    {
        Id = q.Id;
        Description = q.Description;
        CreatedFrom = q.CreatedFrom;
        Type = q.Type;
        AddedTime = q.AddedTime;
        DeletedTime = q.DeletedTime;
        SortIndex = q.SortIndex;
        IsPageBreak = q.IsPageBreak;

        List<QuestionAlternative> list = new List<QuestionAlternative>();
        QuestionAlternative alternative;
        foreach (var alt in q.Alternatives)
        {
            alternative = new QuestionAlternative(alt);
            alternative.Id = 0;
            list.Add(alternative);
        }
        Alternatives = list;
    }

The QuestionAlternative in turn has a copy constructor as so:

    public QuestionAlternative(QuestionAlternative qa)
    {
        Id = qa.Id;
        Text = qa.Text;
        HasTextAnswer = qa.HasTextAnswer;
    }
2
  • Can you show the cloning code inside your copy constructor? Commented Sep 24, 2013 at 8:22
  • Happily, I updated the question Commented Sep 24, 2013 at 9:08

1 Answer 1

2

I think your problem is here:

"While cloning I copy the reference for CreatedFrom however that should be null in the object being cloned"

The value that oldQ.CreatedFrom references might be null at the point that the constructor is called, but it is still a reference type. So when you call q.CreatedFrom = oldQ then oldQ.CreatedFrom is also set to the same reference - i.e. it will refer to itself.

If you add the CreatedFromID as a property on the Question and use that instead, then I think Entity Framework will fix up your references for you. So the properties should look like this:

public int? CreatedFromID { get; set; }

[ForeignKey("CreatedFromID ")]
public virtual Question CreatedFrom { get; set; }

And in your constructor:

public Question(Question q)
{
   //Stop setting the reference property
   //CreatedFrom = q.CreatedFrom;

   //Set the foreign key instead        
   CreatedFromID = q.CreatedFromID;

   //EDIT - as discussed in the comments it would make more sense like:
   //CreatedFromID = q.ID;

}

This is worth a read Save the Grief and Use That Foreign Key

EDIT

You don't have to add the foreign key to solve this problem. If you set the references to the logically correct thing in the first place then that should fix it too.

public Question(Question q)
{
    Id = 0;
    CreatedFrom = q;
}
Sign up to request clarification or add additional context in comments.

7 Comments

I am trying your solution but when i run a migration update I get this "Sequence contains no elements" on Add-Migration.
Sounds like a problem in your Seed method to me
It would but my seed is empty.this describes my problem but i did not rename the ID so does not make complete sense: entityframework.codeplex.com/workitem/569
So I changed the name to CreatedFromQuestion and CreatedFromQuestionId. I no longer got the error (don't know why) and it all seems to work great. I really dislike having to put foreignkey in my entities tho as the entities should be fully storage unaware. But I am running out of time and this works.
Actually, the root cause here is that you set the CreatedFrom reference to the wrong thing. It isn't created from the old question's old question. It's created from the old question, and it shouldn't have the old question's id either should it? I will add some example code
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.