Saving individual objects at once using Entity Framework code

I am using Entity Framework 4.3.1 in a project, using code and the DbContext API first. My application is an n-tier application in which disconnected objects can come from the client. I am using SQL Server 2008 R2, but will move on to SQL Azure soon. I am facing a problem that I just cannot solve.

Imagine that I have several classes:

class A {
    // Random stuff here
}
class B {
    // Random stuff here
    public A MyA { get; set; }
}
class C {
    // Random stuff here
    public A MyA { get; set; }
}

By default, EF works with object graphs. For example, if I have an instance of B that encapsulates an instance of A and I call it myDbSet.Add(myB);, it will also mark the instance of A as added (if it is not already monitored).

, , , . :

A myA = new A(); // Represents something already in DB that doesn't need to be udpated.
C myC = new C() { // Represents something already in DB that DOES need to be updated.
    A = myA;
}
B myB0 = new B() { // Not yet in DB.
    A = myA;
}
B myB1 = new B() { // Not yet in DB.
    A = myA;
}

myDbSetC.Attach(myC);
context.Entry(myC).State = Modified;

myDbSetB.Add(myB0); // Tries to track myA with a state of Added
myDbSetB.Add(myB1);

context.SaveChanges();

AcceptChanges cannot continue because the object key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges. , , add myB0 A , A, .

- call myDbSet.AddOnly(myB), , , .

:

# 1: -, , myA .

private void MarkGraphAsUnchanged<TEntity>(TEntity entity) where TEntity : class {
        DbEntityEntry entryForThis = this.context.Entry<TEntity>(entity);
        IEnumerable<DbEntityEntry> entriesItWantsToChange = this.context.ChangeTracker.Entries().Distinct();

        foreach (DbEntityEntry entry in entriesItWantsToChange) {
            if (!entryForThis.Equals(entry)) {
                entry.State = System.Data.EntityState.Unchanged;
            }
        }
    }

...

myDbSetB.Add(myB0);
MarkGraphAsUnchanged(myB0);

myA, - ObjectStateManager.

# 2: , , "" " ". , myB0.A = null, .

# 3: TransactionScope DbContext. SaveChanges() Attach() Add(), , , # 1.

# 4: TransactionScope, , /DAO DbContext SaveChanges() , . " , ". SQL Profiler , SaveChanges() , ( Add()), UPDATE SQL - doesn 't . ​​Entity Framework .

# 5: TransactionScope DbTransaction. - , EntityConnection , ( EntityConnection, ). , , , , , . dev , , Attach() ( - - ).

!! , , , DAO INSERT, UPDATE DELETE, . , Entity Framework O/R, !

+5
2

- , , , . myA, myC, myB0 myB1 myC .

myDbSetC.Attach(myC);
context.Entry(myC).State = Modified;

, , ( ObjectContext API) ( ), myB0 myB1 :

myDbSetB.Add(myB0);
myDbSetB.Add(myB1);

myA myC , , :

C myC = new C() { 
    A = myA;
}

, , API DbContext API. , , , - . , ObjectContext:

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;

ObjectStateManager .

+2

, , , As.

, B0 B1 ( D0 D1), , , A. D0 D1 , Entity.

B0/B1 D0/D1 . API-. Ladislav ObjectStateEntry D0/D1, Unchanged, D0/D1 A Unchanged. , : C B0/B1.

, SaveChanges. , , , , , , .

// Entries are put in here when they are explicitly added, modified, or deleted.
private ISet<DbEntityEntry> trackedEntries = new HashSet<DbEntityEntry>();
private void MarkGraphAsUnchanged()
{
    IEnumerable<DbEntityEntry> entriesItWantsToChange = this.context.ChangeTracker.Entries().Distinct();
    foreach (DbEntityEntry entry in entriesItWantsToChange)
    {
        if (!this.trackedEntries.Contains(entry))
        {
            entry.State = System.Data.EntityState.Unchanged;
        }
    }

    IEnumerable<ObjectStateEntry> allEntries =
            this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
            .Union(this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted))
            .Union(this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified));

        foreach (ObjectStateEntry entry in allEntries)
        {
            if (entry.IsRelationship)
            {
                /* We can't mark relationships are being unchanged if we are truly adding or deleting the entity.
                 * To determine this, we need to first lookup the entity keys, then state entries themselves.
                 */
                EntityKey key1 = null;
                EntityKey key2 = null;
                if (entry.State == EntityState.Deleted)
                {
                    key1 = (EntityKey)entry.OriginalValues[0];
                    key2 = (EntityKey)entry.OriginalValues[1];
                }
                else if (entry.State == EntityState.Added)
                {
                    key1 = (EntityKey)entry.CurrentValues[0];
                    key2 = (EntityKey)entry.CurrentValues[1];
                }

                ObjectStateEntry entry1 = this.context.ObjectContext.ObjectStateManager.GetObjectStateEntry(key1);
                ObjectStateEntry entry2 = this.context.ObjectContext.ObjectStateManager.GetObjectStateEntry(key2);

                if ((entry1.State != EntityState.Added) && (entry1.State != EntityState.Deleted) && (entry2.State != EntityState.Added) && (entry2.State != EntityState.Deleted))
                {
                    entry.ChangeState(EntityState.Unchanged);
                }
            }
        }
    }

!!! :

  • .
  • , Entity , , .
  • .

" " , , -, , ( D0/D1), . - . , Entity ( , ).

0

All Articles