Mappage un à zéro ou un avec EF7

Je suis actuellement en train de nettoyer une database assez volumineuse. Une partie de la database a une relation qui est un mappage de un à zéro ou un. Plus précisément:

User -> UserSettings 

Tous les users n'auront pas de parameters user, mais un paramètre user ne peut pas exister sans l'user. Malheureusement, les tables existent déjà. User a un identifiant PK. UserSettings a un PK ID et une colonne, User_Id_Fk qui, à ce moment-là, n'est pas un vrai FK (il n'y a pas de relation définie).

Je suis en train de corriger cela et l'ai fait à partir de la perspective DB via SQL et j'ai confirmé avec des tests. (Ajout de la contrainte FK.) Ajout d'une contrainte unique sur User_Id_Fk .) Tout a été fait dans la table UserSettings . (Note: Je n'utilise pas les Migrations EF ici, je dois écrire manuellement le SQL à ce moment-là.)

Cependant, je dois maintenant câbler une application existante pour gérer correctement ce nouveau mappage. L'application utilise ASP.NET Core 1.0 et EF7. Voici des versions (raccourcies) des templates de données existants.

 public class User { public int Id { get; set; } public virtual UserSettings UserSettings { get; set; } } public class UserSettings { public int Id { get; set; } [Column("User_Id_Fk")] public int UserId { get; set; } [ForeignKey("UserId")] public virtual User User { get; set; } } 

J'ai aussi cette cartographie fluide:

 builder.Entity<UserSettings>() .HasOne(us => us.User) .WithOne(u => u.User) .IsRequired(false); 

Quand je vais exécuter l'application et accéder à ces éléments dans la database, je reçois cette erreur suivie d'un set énigmatique de messages qui n'a aucune information directement liée à mon application .:

 ArgumentNullException: Value cannot be null. Parameter name: navigation Microsoft.Data.Entity.Utilities.Check.NotNull[T] (Microsoft.Data.Entity.Utilities.T value, System.Ssortingng parameterName) <0x10d28a650 + 0x00081> in <filename unknown>, line 0 

Après avoir fait des searchs, quelqu'un a mentionné que l'ID de la class UserSettings doit être la même que la key étrangère, comme ceci:

 public class UserSettings { [Key, ForeignKey("User")] public int Id { get; set; } public virtual User User { get; set; } } 

Je n'ai pas vraiment cela en option car la database est utilisée pour d'autres applications sur lesquelles je n'ai aucun contrôle. Alors, suis-je coincé ici? Est-ce que je dois juste maintenir un 1: beaucoup de cartographie (ce qui pourrait arriver maintenant, bien que ce ne soit pas le cas) et ne pas avoir de contraintes appropriées pour un mappage 1: 0..1?

Mise à jour En regardant la réponse d'octavioccl ci-dessous, j'ai essayé sans succès. Cependant, j'ai ensuite supprimé l' User du mappage dans UserSettings (mais j'ai quitté UserId ). Tout a semblé fonctionner autant que je peux dire. Je suis vraiment confus de ce qui se passe ici, cependant, et si c'est la bonne réponse, ou si j'ai juste de la chance.

Supprimez les annotations de données et essayez avec ces configurations:

 builder.Entity<UserSettings>() .Property(b => b.UserId) .HasColumnName("User_Id_Fk"); builder.Entity<User>() .HasOne(us => us.UserSettings) .WithOne(u => u.User) .HasForeignKey<UserSettings>(b => b.UserId); 

De la documentation EF Core :

Lors de la configuration de la key étrangère, vous devez spécifier le type d'entité dépendante. Notez le paramètre générique fourni à HasForeignKey dans la list ci-dessus. Dans une relation un-à-plusieurs, il est clair que l'entité avec la navigation de reference est la dépendante et celle avec la collection est le principal. Mais ce n'est pas le cas dans une relation biunivoque – d'où la nécessité de le définir explicitement.

L'exemple qui est présenté dans le lien cité ( BlogBlogImage ) est à peu près le même que celui que vous essayez d'atteindre.

Si la solution que je montre ci-dessus ne fonctionne pas, alors vous devriez vérifier si la colonne User_Id_Fk autorise null . Si tel est le cas, changez le type de propriété FK en int? :

 public class UserSettings { public int Id { get; set; } public int? UserId { get; set; } public virtual User User { get; set; } }