Entity Framework - l'Insertion d'enregistrements dans la table enfant lors de l'enregistrement parent existe déjà
Bon après-midi-
Je développe une application Silverlight à l'aide de LINQ to Entity Framework pour la couche d'accès aux données. Mon n-tier modèle de base de données comprend environ 30 tables, avec un certain nombre de multi-niveaux des relations parent-enfant tout au long de. Récemment commencé à écrire mes services de données et les tests unitaires, et nous avons découvert un problème avec l'insertion d'un nouvel enregistrement dans une table d'enfant lorsque le parent enregistrement de la table est déjà défini. Voici une version abrégée de mes tables parent et enfant:
TABLE PARENT:
Utilisateurs
id d'utilisateur (PK)
e-Mail
Mot de passe
etc...
TABLE ENFANT:
Userprofile
UserProfileID (PK)
Diverses informations sur le profil...
id d'utilisateur (FK -- table des Utilisateurs)
Donc, à ce moment, j'ai l'Entity Framework a déjà été utilisé pour créer mes différentes classes pour l'ORM, et je suis à la recherche pour créer des services de données pour les opérations CRUD sur mes entités. Voici un exemple de code pour ma méthode pour insérer un nouveau Utilisateur (qui n'a pas de parent références de table):
public User CreateUser(User newUser)
{
using (var _context = new ProjectDatabase())
{
newUser.CreatedDate = DateTime.Now;
newUser.ModifiedDate = DateTime.Now;
_context.AddToUsers(newUser);
_context.SaveChanges();
}
return newUser;
}
Cela fonctionne bien. J'ai écrit des tests unitaires pour ça, pas de problème. Maintenant, d'autre part, considérons les données suivantes de la méthode du service que j'ai écrit pour insérer un nouveau Utilisateur de l'objet dans la base de données. Pour commencer, j'ai une très semblables service de données:
public UserProfile CreateProfile(UserProfile newUserProfile)
{
using (var _context = new ProjectDatabase())
{
newUserProfile.CreatedDate = DateTime.Now;
newUserProfile.ModifiedDate = DateTime.Now;
_context.AddToUserProfiles(newUserProfile);
_context.SaveChanges();
}
return newUserProfile;
}
Ce code, tout comme les autres, se compile sans problème. Cependant, mon test de l'unité ne parvient pas. Voici le code de mon test de l'unité:
[TestMethod]
public void UserProfileCrudTest()
{
IProfileDataService _dataService = new ProfileDataService();
//Pre-seeded data on a State for foreign key
State _myState;
using (var _context = new ProjectDatabase())
{
_myState = _context.States.First();
}
//Creating temporary User for association with new UserProfile
User _myUser = new User()
{
Email = "test",
Password = "test",
IsActive = true,
NameFirst = "test",
NameLast = "test"
};
_myUser = _dataService.CreateUser(_myUser);
Assert.IsNotNull(_myUser);
//Attempt to create new UserProfile, assigning foreign key
_myUserProfile = new UserProfile()
{
Address = "123 Main",
City = "Anywhere",
State = _myState,
PostalCode = "63021",
UserID = _myUser.UserID
};
//This call to CreateProfile throws an exception and the test fails!!
_myUserProfile = _dataService.CreateProfile(_myUserProfile);
Assert.IsNotNull(_myUserProfile);
//Remaining test code... never gets this far...
}
Donc, à ce moment, mon test de l'unité déclenche l'exception suivante:
Méthode d'essai MyProject.Data services.Les Tests.SecurityTests.UserProfileCrudTest jeté exception:
Système.InvalidOperationException: Le EntityKey de propriété ne peut être réglé que lorsque la valeur actuelle de la propriété est null.
Ce que je comprends de mes recherches jusqu'à présent, c'est en quelque sorte attachant retour à la propriété de navigation qui associe la nouvelle de l'Utilisateur de l'objet avec l'Utilisateur.Userprofile collection sur la table parent/objet. Mais je ne suis pas sûr de ce que des mesures sont nécessaires pour résoudre le problème. Dois-je en quelque sorte besoin de joindre le parent à ObjectContext? Toute aide serait GRANDEMENT appréciée!
Grâce,
Jeff S.
OriginalL'auteur jeffreystrauss | 2010-08-26
Vous devez vous connecter pour publier un commentaire.
Vous n'avez pas besoin de faire ce genre de choses. Avec EF 4.0 votre code pourrait être aussi simple que cela:
Explication:
Ce que vous avez fait est bien sens typique données de scénarios d'accès, où vous devez d'abord insérer la nouvelle Utilisateur, récupérer son UserID, et ensuite l'utiliser pour insérer la nouvelle UserProfile. Cependant, SaveChanges fait tout cela pour vous quand il voit que les deux
sont nouveaux et qu'ils sont liés. Il utilise également le modèle de mappages de comprendre ce qui
est dépendante de l'entité (dans ce cas, UserProfile) et a besoin de la clé étrangère (UserID).
Avec cette information, il exécute la base de données insère dans le bon ordre.
L'ajout d'un nouveau profil Utilisateur à un Utilisateur existant:
Si vous voulez ajouter un nouvel Utilisateur à un Utilisateur existant et vous avez déjà l'objet Utilisateur que vous souhaitez ajouter le profil, il vous suffit de les relier par écrit:
puis d'appeler la SavingChanges().
Si vous n'avez que le nom d'utilisateur, vous pouvez le définir comme UserProfile.UserID = userID. BTW, je suis conscient que c'est ce que vous avez initialement essayé de le faire et vous avez obtenu une exception, voici ce que vous devez faire:
1. Mise à jour de votre Modèle à partir de la base de données pour vous assurer que votre modèle est entièrement à la synchronisation avec votre DB.
2. Étape votre code et assurez-vous que vous définissez un légitime UserID de l'Utilisateur de l'objet (quelque chose qui existe vraiment dans la Table User) - vous pouvez même essayer de coder en dur.
3. Exécutez-le à nouveau et si vous êtes toujours obtenir de l'exception, alors postez votre trace de la pile depuis j'ai couru votre code et je ne reçois pas tout, de sorte que votre exception peut-être à venir à partir d'une toute autre question.
Pas de problème. Basé sur votre code, j'ai pensé que vous êtes plus intéressés à insérer deux nouveaux objets dépendants et mon point est que vous pouvez les enregistrer dans son ensemble comme vous les lire comme un tout avec EF. J'ai édité ma réponse à l'adresse du scénario de mise à jour, merci de lui donner un essai et laissez-moi savoir comment cela fonctionne pour vous. Merci.
OriginalL'auteur Morteza Manavi