title: Tell DbContext to not add whole object graph?
body: <p>I have a class in my model that can refer to the same child class from two different FK associations/fields. Both of these references are populated with the same instance of the child object when the parent is created, and then later, one of the two children can be updated or changed (this does <em>not</em> always happen), and the original is kept because the other of the children is never touched. I hope that makes sense.</p>
  
  <p>When a Parent is created or pulled from the database that has the same Child referenced twice, when you try to add the Parent to the DbContext we're seeing the dreaded error: <code>An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.</code> This is being thrown because the DbContext is trying to add the entire object graph to its change tracker, i.e. the two Child references pointing to the same Child object.</p>
  
  <p>We don't need change tracking. We don't mind throwing a fully populated UPDATE statement at the database. Is there a way to force the DbContext to not add the entire object graph, to only add the single instance we're telling it to add? If so, what functionality are we going to lose if we disable this globally?</p>
  
  <p><strong>EDIT:</strong> Updated code sample.</p>
  
  <p><strong>EDIT 2:</strong> Updated code sample to include serialization to mimic web service interaction.</p>
  
  <pre><code>[TestClass]
  public class EntityFrameworkTests
  {
    [TestMethod]
    public void ObjectGraphTest()
    {
      Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
      Database.SetInitializer(new DropCreateDatabaseAlways&lt;MyDbContext&gt;());
  
      string connectionString = String.Format("Data Source={0}\\EntityFrameworkTests.sdf", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
      MyDbContext context = new MyDbContext(connectionString);
  
      Child child = new Child() { ID = 1, SomeProperty = "test value" };
      //context.Entry&lt;Child&gt;(child).State = EntityState.Added;
      Parent parent = new Parent()
      {
        ID = 1,
        SomeProperty = "some value",
        OriginalChild = child,
        ChangeableChild = child
      };
      context.Entry&lt;Parent&gt;(parent).State = EntityState.Added;
      context.SaveChanges();
  
      context = new MyDbContext(connectionString);
      //parent = context.Set&lt;Parent&gt;().AsNoTracking().Include(p =&gt; p.OriginalChild).Include(p =&gt; p.ChangeableChild).FirstOrDefault();
      parent = context.Set&lt;Parent&gt;().Include(p =&gt; p.OriginalChild).Include(p =&gt; p.ChangeableChild).FirstOrDefault();
  
      // mimic receiving object via a web service
      SaveToStorage(parent);
      parent = GetSavedItem(1);
  
      parent.SomeProperty = "some new value";
      context = new MyDbContext(connectionString);
      context.Entry&lt;Parent&gt;(parent).State = EntityState.Modified; // error here
      context.SaveChanges();
    }
  }
  </code></pre>
  
  <p>Serialization methods to mimic web service interaction:</p>
  
  <pre><code>private void SaveToStorage(Parent parent)
  {
    string savedFilePath = String.Format("{0}\\Parent{1}.xml", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), parent.ID);
  
    using (FileStream fileStream = new FileStream(savedFilePath, FileMode.Create, FileAccess.Write))
    {
      using (XmlWriter writer = XmlWriter.Create(fileStream))
      {
        DataContractSerializer serializer = new DataContractSerializer(typeof(Parent));
        serializer.WriteObject(writer, parent);
      }
    }
  }
  
  private Parent GetSavedItem(int parentID)
  {
    string savedFilePath = String.Format("{0}\\Parent{1}.xml", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), parentID);
  
    using (FileStream fileStream = new FileStream(savedFilePath, FileMode.Open, FileAccess.Read))
    {
      using (XmlDictionaryReader xmlReader = XmlDictionaryReader.CreateTextReader(fileStream, new XmlDictionaryReaderQuotas()))
      {
        DataContractSerializer serializer = new DataContractSerializer(typeof(Parent));
        Parent savedItem = (Parent)serializer.ReadObject(xmlReader, true);
        return savedItem;
      }
    }
  }
  </code></pre>
  
  <p>Classes used (updated for serialization):</p>
  
  <pre><code>[DataContract]
  internal class Child
  {
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string SomeProperty { get; set; }
  }
  
  [DataContract]
  internal class Parent
  {
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string SomeProperty { get; set; }
  
    [DataMember]
    public int OriginalChildID { get; set; }
    [DataMember]
    public Child OriginalChild { get; set; }
    [DataMember]
    public int ChangeableChildID { get; set; }
    [DataMember]
    public Child ChangeableChild { get; set; }
  }
  
  internal class MyDbContext : DbContext
  {
    public DbSet&lt;Parent&gt; Parents { get; set; }
    public DbSet&lt;Child&gt; Children { get; set; }
  
    public MyDbContext(string connectionString)
      : base(connectionString) { }
  
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      modelBuilder.Conventions.Remove&lt;OneToManyCascadeDeleteConvention&gt;();
    }
  }
  </code></pre>