Entity Framework Anhängen eines persistenten Objekts an das neue Objekt

entity entity-framework

Frage

Ich versuche, eine sehr einfache Aufgabe auszuführen, nämlich "Hinzufügen des Benutzers mit Rolle in der Datenbank". Die Rollen sind bereits in der Datenbank ausgefüllt, und ich füge die Rolle einfach zur Sammlung der Benutzerrollen hinzu, es wird jedoch die folgende Ausnahme ausgelöst:

Die EntityKey-Eigenschaft kann nur festgelegt werden, wenn der aktuelle Wert der Eigenschaft null ist.

Hier ist der Code in User.cs:

  public void AddRole(Role role)
        {
            if (!Exists(role))
            {
                 role.User = this;
                Roles.Add(role);                 
            }
        }

Und hier ist der Test, der fehlschlägt:

  [Test]        
        public void should_save_user_with_role_successfully() 
        {
            var _role = _roleRepository.GetByName("Student");                        

            _user.AddRole(_role); 

            _userRepository.Save(_user);

            Assert.IsTrue(_user.UserId > 0);             
        }

Der Repository-Code:

  public bool Save(User user)
        {
            bool isSaved = false; 

            using (var db = new EStudyDevDatabaseEntities())
            {   
                db.AddToUsers(user);
                isSaved = db.SaveChanges() > 0;  
            }

            return isSaved; 

        }

Hier ist die AddRole-Methode:

   public bool Exists(Role role)
        {
            var assignedRole = (from r in Roles
                                where r.RoleName.Equals(role.RoleName)
                                select r).SingleOrDefault();

            if (assignedRole != null) return true;

            return false; 
        }

        public void AddRole(Role role)
        {
            if (!Exists(role))
            {
                 role.User = this;
                Roles.Add(role);                 
            }
        }

Und hier ist die ganze Ausnahme:

------ Test started: Assembly: EStudy.Repositories.TestSuite.dll ------

TestCase 'EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully'
failed: System.InvalidOperationException : The EntityKey property can only be set when the current value of the property is null.
 at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
 at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
 at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
 at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
 at System.Data.Objects.DataClasses.EntityObject.set_EntityKey(EntityKey value)
 at System.Data.Objects.Internal.LightweightEntityWrapper`1.set_EntityKey(EntityKey value)
 at System.Data.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
 at System.Data.Objects.ObjectContext.AddSingleObject(EntitySet entitySet, IEntityWrapper wrappedEntity, String argumentName)
 at System.Data.Objects.DataClasses.RelatedEnd.AddEntityToObjectStateManager(IEntityWrapper wrappedEntity, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelatedEnd.AddGraphToObjectStateManager(IEntityWrapper wrappedEntity, Boolean relationshipAlreadyExists, Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelationshipManager.AddRelatedEntitiesToObjectStateManager(Boolean doAttach)
 at System.Data.Objects.ObjectContext.AddObject(String entitySetName, Object entity)
 C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Entities\EStudyModel.Designer.cs(97,0): at EStudy.BusinessObjects.Entities.EStudyDevDatabaseEntities.AddToUsers(User user)
 C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Repositories\UserRepository.cs(17,0): at EStudy.BusinessObjects.Repositories.UserRepository.Save(User user)
 C:\Projects\EStudy\EStudySolution\EStudy.Repositories.TestSuite\Repositories\Test_UserRepository.cs(47,0): at EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully()


0 passed, 1 failed, 0 skipped, took 6.07 seconds (NUnit 2.5).

AKTUALISIEREN:

Hier ist mein UserRepository und RoleRepository und beide verwenden getrennte Kontexte:

  public bool Save(User user)
        {
            bool isSaved = false; 

            using (var db = new EStudyDevDatabaseEntities())
            {              
                db.AddToUsers(user);
                isSaved = db.SaveChanges() > 0;  
            }

            return isSaved; 

        }

 public Role GetByName(string roleName)
        {
            using (var db = new EStudyDevDatabaseEntities())
            {
                return db.Roles.SingleOrDefault(x => x.RoleName.ToLower().Equals(roleName.ToLower())); 
            }           
        }

Sie sehen, dass der Benutzer und die Rolle einen anderen Kontext verwenden, auf den Sie bereits hingewiesen haben. Das Problem bei der Verwendung eines einzelnen Datenkontexts besteht darin, dass ich die Anwendung nicht richtig schichten kann.

Akzeptierte Antwort

Erneut aktualisiert aufgrund der aktualisierten Frage

Ich stimme nicht zu, dass Sie die Anwendung "nicht richtig schichten können", wenn Sie einen Kontext zwischen Repositorys freigeben. Es ist ein Problem, das Sie lösen müssen, aber es ist höchst sicher lösbar. Ich denke, Sie werden es wesentlich einfacher zu lösen finden als die Anzahl der Probleme, die Sie beim Versuch, mehrere Kontexte zu verwenden, verursachen.

In jedem Fall gibt es wirklich nur zwei mögliche Lösungen für Ihr Problem:

  1. Verfolgen Sie manuell den Kontext, an den eine bestimmte Entität angehängt ist, und übertragen Sie sie bei Bedarf (mit Anhängen und Trennen).
  2. Teilen Sie einen Kontext zwischen Repository-Instanzen.

In unseren ASP.NET-MVC-Anwendungen ist die logische Arbeitseinheit eine einzige Anforderung. Daher wird ein ObjectContext zu Beginn einer Anforderung instanziiert, am Ende einer Anforderung entsorgt und bei der Erstellung in neue Repositorys eingefügt. Repository-Instanzen dauern niemals eine einzelne Anforderung.

Update basierend auf der aktualisierten Frage

Haben das Rollen-Repository und das Benutzer-Repository jeweils einen (separaten) Kontext? Was passiert in der Stack-Ablaufverfolgung:

  1. Sie fügen den Benutzer zum Kontext hinzu.
  2. Der RelationshipManager durchläuft den Benutzer und stellt sicher, dass alle zugehörigen Entitäten sich auch im Kontext befinden. Dazu wird unter anderem die EntityKey-Eigenschaft festgelegt.
  3. Vorausgesetzt, dass die Rolle aus einem anderen Kontext stammt (was offensichtlich der Fall ist, da der Kontext andernfalls erkennen sollte, dass sich die Rolle bereits im Kontext befindet), sollte ein Fehler angezeigt werden, der angibt, dass Sie keine Entität hinzufügen können, die einem Kontext zugeordnet ist ein anderer Kontext. Aus irgendeinem Grund sieht man das hier nicht. Trotzdem ist es keine gültige Operation.
  4. Stattdessen wird eine Fehlermeldung angezeigt, wenn der EntityKey der Rolle zugewiesen wird.

Meiner Meinung nach sollte die Verwendung eines einzelnen ObjectContext zu einem Zeitpunkt die allgemeine Regel für das Arbeiten mit dem EntityFramework sein. Sie sollten nur dann mehrere Kontexte verwenden, wenn Sie absolut dazu gezwungen sind. Dies ist meiner Erfahrung nach fast nie der Fall. Das gleichzeitige Arbeiten mit mehreren ObjectContexts ist erheblich schwieriger als das gleichzeitige Arbeiten.

OK, ich kenne die Details Ihres Mappings nicht, aber ich würde erwarten, dass AddRole mehr im Sinne von:

public void AddRole(Role role)
{
    this.Roles.Add(role);
}

... wenn Benutzer-> Rolle ist .. oder:

public void AddRole(Role role)
{
    this.Role = role;
}

wenn Benutzer -> Rolle ist * .. 1.

Wenn dies nicht hilft, buchen Sie den Stack-Trace für die Ausnahme.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum