1

Je vais essayer de ne mettre ici que les parties pertinentes du modèle, car il y a beaucoup de classes. Espérons que il suffit de saisir le problème:Code EF6 Tout d'abord, plusieurs chemins en cascade, et un comportement FK étrange

public class Solve 
{ 
    public int SolveID { get; set; } 

    public int LocationID { get; set; } 
    public virtual Location Location { get; set; } 

    public int ProfileID { get; set; } 
    public virtual Profile Profile { get; set; } 

    public int BillID { get; set; } 
    public virtual Bill Bill { get; set; } 

    public int? PanelID { get; set; } 
    public virtual Panel Panel { get; set; } 
} 

public class Location 
{ 
    public int LocationID { get; set; } 

    [Index] 
    [StringLength(48)] 
    public string Name { get; set; } 

    [Index] 
    public State State { get; set; } 

    public double Latitude { get; set; } 
    public double Longitude { get; set; } 

    public virtual List<Profile> Profiles { get; set; } 
} 

public class Profile 
{ 
    public int ProfileID { get; set; } 

    public int LocationID { get; set; } 
    public virtual Location Location { get; set; } 

    public double Capacity { get; set; } 

    public virtual List<ProfileSample> ProfileSamples { get; set; } 
} 

public class ProfileSample 
{ 
    [Key, ForeignKey("Profile")] 
    [Column(Order = 1)] 
    public int ProfileID { get; set; } 
    public virtual Profile Profile { get; set; } 

    [Key] 
    [Column(Order = 2)] 
    [DataType(DataType.Date)] 
    public DateTime Date { get; set; } 

    [Key] 
    [Column(Order = 3)] 
    public TimeSpan TimeOfDay { get; set; } 

    public double SampleValue { get; set; } 
} 

Il était tout fonctionne bien jusqu'à ce que je présenté au cours de laquelle la classe Solve point il a commencé à se plaindre de « plusieurs chemins en cascade ». J'ajouté ce qui suit au contexte et il semblait être OK à partir de là:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Solve>() 
     .HasRequired(s => s.Location) 
     .WithRequiredDependent() 
     .WillCascadeOnDelete(false); 
} 

Sauf qu'il était le comportement anormal:

using (Model.BlueData bd = new Model.BlueData()) 
{ 
    Random rng = new Random(); 

    s = new Model.Solve() 
    { 
     Location = bd.Locations.Find(rng.Next(0, bd.Locations.Count())), 
     Bill  = bd.Bills.Find(rng.Next(0, bd.Bills.Count())), 
     Profile = bd.Profiles.Find(rng.Next(0, bd.Profiles.Count())) 
    }; 

    bd.Solves.Add(s); 
    bd.SaveChanges(); 

    s = bd.Solves 
     .Where(u => u.SolveID == s.SolveID) 
     .Include(u => u.Location) 
     .Include(u => u.Profile) 
     .Include(u => u.Profile.ProfileSamples) 
     .Include(u => u.Bill) 
     .FirstOrDefault(); 
} 

Ainsi, le code ci-dessus génère juste un objet aléatoire Solve , l'ajoute au contexte de données, puis le récupère à nouveau avec toutes les données associées. Il y a certainement une façon plus élégante de le faire, mais pour le moment, il s'agit juste de tester le code pour s'assurer que les autres parties de mon application fonctionnent.

Alors comme prévu, lorsque je crée l'objet Solve s, s.Location est un endroit particulier, avec ID, disons, 1609, et bien sûr s.LocationID et s.SolveID tous deux égaux 0. En l'ajoutant au contexte de données et en sauvegardant les modifications, le s.SolveID est égal à l'ID du lieu (1609, dans cet exemple). C'est très étrange. J'ai essayé d'ajouter un attribut [Key] à SolveID et [ForeignKey("Location")] à LocationID dans la classe Solve, mais cela n'a fait aucune différence.

J'ai essayé diverses choses comme enlever Profile de Solve, ou enlever le List<Profile> Profiles de Location. Je ne me souviens pas maintenant exactement, mais quelques choses ont fonctionné pour corriger le s.SolveID réglé au comportement d'identification de l'endroit.

Mais ces propriétés sont toutes là pour une raison, et si possible, je préfère ne pas avoir à les supprimer juste pour que cela fonctionne. Je ne comprends pas pourquoi cela se passe, ou comment le corriger correctement. J'apprécie toute aide.

+0

Je pense que la clé étrangère devra être rajoutées, l'éther comme annotion de données (que vous avez déjà tried- et je pensais était le solution) ou peut-être l'ajouter en utilisant l'api fluide fonctionnerait. cela pourrait aussi le réparer: http://stackoverflow.com/questions/21229373/ef-foreign-key-using-fluent-api –

Répondre

2

Tout d'abord Location est renvoyé dans Solve objet, donc l'emplacement est le principal et Solve dépend, je pense que dans ce cas, cette cartographie est erroné -

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Solve>() 
     .HasRequired(s => s.Location) 
     .WithRequiredDependent() 
     .WillCascadeOnDelete(false); 
} 

Il devrait être -

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Solve>() 
     .HasRequired(s => s.Location) 
     .WillCascadeOnDelete(false); 
} 

Deuxièmement, puisque Solve référençant avec la clé étrangère la définition devrait être -

public class Solve 
{ 
    public int SolveID { get; set; } 

    [ForeignKey("Location")] 
    public int LocationID { get; set; } 
    public virtual Location Location { get; set; } 

    [ForeignKey("Profile")] 
    public int ProfileID { get; set; } 
    public virtual Profile Profile { get; set; } 

    [ForeignKey("Bill")] 
    public int BillID { get; set; } 
    public virtual Bill Bill { get; set; } 

    [ForeignKey("Panel")] 
    public int? PanelID { get; set; } 
    public virtual Panel Panel { get; set; } 
} 

Troisièmement, lors de la sauvegarde d'objets, vous devez d'abord enregistrer les 1) principaux, sinon EF tentera de créer de nouvelles entrées ou 2) vous devrez les attacher manuellement. Parmi ceux-ci, le plus simple que j'ai trouvé est (1), après avoir enregistré la fin principale, je n'attribue que la clé étrangère et EF fonctionne comme prévu.

using (Model.BlueData bd = new Model.BlueData()) 
{ 
    Random rng = new Random(); 

    s = new Model.Solve() 
    { 
     LocationID = bd.Locations.Find(rng.Next(0, bd.Locations.Count())).LocationID, 
     BillID  = bd.Bills.Find(rng.Next(0, bd.Bills.Count())).BillID, 
     ProfileID = bd.Profiles.Find(rng.Next(0, bd.Profiles.Count())).ProfileID 
    }; 
    s.Bill = s.Location = s.Profile = null; //otherwise EF tries to create them 
    bd.Solves.Add(s); 
    bd.SaveChanges(); 

    s = bd.Solves 
     .Where(u => u.SolveID == s.SolveID) 
     .Include(u => u.Location) 
     .Include(u => u.Profile) 
     .Include(u => u.Profile.ProfileSamples) 
     .Include(u => u.Bill) 
     .FirstOrDefault(); 
} 

EDIT 1: La classe d'emplacement pour être -

public class Location 
{ 
    [Key] //mark location ID as primary key 
    public int LocationID { get; set; } 

    [Index] 
    [StringLength(48)] 
    public string Name { get; set; } 

    [Index] 
    public State State { get; set; } 

    public double Latitude { get; set; } 
    public double Longitude { get; set; } 

    public virtual List<Profile> Profiles { get; set; } 
} 
+0

Merci beaucoup pour votre réponse. Cette ligne: 's.Bill = s.Location = s.Profile = null;', est-ce nécessaire? Vous avez dit que EF essaierait de les créer, mais ils devraient déjà être "null", n'est-ce pas? – Ozzah

+0

Oui, mais juste pour s'assurer qu'ils sont nuls. Vous n'allez pas avoir le même code partout. Et si cela a résolu votre problème, veuillez accepter comme réponse, alors d'autres personnes ayant le même problème savent que cela pourrait être une solution. –

+0

J'ai implémenté les modifications que vous avez recommandées, et maintenant j'obtiens l'erreur: Solve_Location_Source:: La multiplicité n'est pas valide dans le rôle 'Solve_Location_Source' dans la relation 'Solve_Location'. Comme les propriétés du rôle dépendant ne sont pas les propriétés clés, la limite supérieure de la multiplicité du rôle dépendant doit être '*'. – Ozzah