2017-09-19 8 views
1

Je semble être aux prises avec une combinaison de conventions de dénomination et de compréhension.Mise à jour d'une relation plusieurs-à-plusieurs ni entièrement de code ni de base de données d'abord

J'ai hérité d'une base de données et je construis un site MVC que je n'ai pas réussi à faire fonctionner correctement le flux de travail "database-first". À la fin, j'ai construit manuellement mes classes de contexte et j'ai travaillé avec bonheur.

Je suis maintenant dans une situation où je suis incapable d'ajouter une entité avec une relation à plusieurs autres entités existantes (le plusieurs-à-plusieurs).

Mes regards de base de données (simplifié pour cette question) comme celle-ci:

ListItem  Option  OptionListItems 
======  ======  =============== 
Id   Id   ListItem_Id 
Name   Name   Option_Id 

Mon contexte contient une propriété qui me permet d'obtenir tous mes ListItems:

public virtual DbSet<ListItem> ListItems { get; set; } 

Et si j'utilise quelques LINQ, je fais quelque chose comme ce qui suit, et les articles sont retournés et la relation many-to-many est satisfaite et je reçois une liste de Option au sein de mon :

var item = _context.ListItems 
.Where(p => p.Id == id) 
.Include(p => p.Options) 
.SingleOrDefault(); 

En fait, je devais construire manuellement la table de références croisées dans la base de données que j'ai faite quand j'ai essayé d'exécuter la requête ci-dessus et l'exception que je me suis faite ne s'appelait pas dbo.OptionListItems. Donc j'ai supposé que nous étions tous bons.

Maintenant, je dois créer un nouveau ListItem et le lier à un ou plusieurs existantsOption et je suis à une perte.

Une fois que je l'ai créé mon nouveau ListItem en vase clos et tentative d'appel échoue listItem.Options.Add(...), mais je reçois aussi la même exception exacte si je tente d'obtenir une référence à un Option particulier et essayer de faire option.ListItems.Add(...).

L'erreur est plutôt amusant et est le nom de la table en face de ce que j'ai:

{"Invalid object name 'dbo.ListItemOptions'."} 

Je pense qu'il va à l'encontre du grain de EF pour construire un type et une propriété sur mon contexte directement accéder à la table de référence croisée comme ceci:

public virtual DbSet<OptionListItem> OptionListItems { get; set; } 

Mais je suis complètement déconcerté par le modèle pour créer de nouvelles relations.

+0

Je ne sais pas comment vous arrachaient la première substance DB, mais dans le code d'abord si vous avez besoin de contrôler le nombre à plusieurs, vous aurez besoin du code de carte couramment comme [ce] (http: //www.entityframeworktutorial .net/code-first/configure-many-à-many-relation-in-code-first.aspx) (près du bas). –

+0

Oui, c'est une situation étrange. J'avais une base de données et quelques POCO créés manuellement, donc en plus de cela j'ai ajouté manuellement des bits aux deux côtés plutôt que de compter sur des échafaudages ou des migrations. Avant d'essayer de créer le mappage (j'ai vu ce post mais je n'étais pas sûr que c'était la meilleure approche), quel est le modèle à utiliser? Ai-je raison de prendre mes 'ListItem' et' .Add'ing à la collection Options - et donc avec le mapping cela devrait fonctionner? – Neil

Répondre

0

Nous avons ceci (many-to-many) fonctionnellement. Pseudocode:

public class ListItem 
{ 

    public ListItem() 
    { 
     this.RelatedOptions = new HashSet<OptionListItems>(); 
    } 

    [Key] 
    public int Id {get; set;} 
    public string Name {get; set;} 
    public virtual ICollection<OptionListItems> RelatedOptions {get; set;} 
} 

public class Option 
{ 
    public Ortion() 
    { 
     this.RelatedItems = new HashSet<OptionListItems>(); 
    } 

    [Key] 
    public int Id {get; set;} 
    public string Name {get; set;} 
    public virtual ICollection<OptionListItems> RelatedItems {get; set;} 
} 


public class OptionListItems 
{ 
    [Key] 
    public int Id {get; set;} 

    [Column("ListItemId", Order = 1)] 
    [ForeignKey("ParentListItem")] 
    public int ListItemId {get; set;} 

    [Column("OptionId", Order = 2)] 
    [ForeignKey("ParentOption")] 
    public int OptionId {get; set;} 

    public virtual ListItem ParentListItem {get; set;} 
    public virtual Option ParentOption {get; set;} 
} 

Cela devrait créer la relation complète déclarative

+0

Merci - j'avais déjà un modèle très similaire, mais ce post m'a au moins aidé à le valider. – Neil

0

Le crédit va à Steve Greene pour moi pointant dans la bonne direction. La table que j'avais était créée par convention et a fonctionné quand j'ai interrogé WorkItem avec .Include(p => p.Options) cependant la convention semble tomber en panne si vous essayez de faire une mise à jour. Je ne sais pas pourquoi, mais la construction de la table de mappage semble être <Entity1>+<Entity2>+s lors de l'interrogation, mais <Entity2>+<Entity1>+s lors de la mise à jour ...La bonne nouvelle, en utilisant fluentAPI, j'ai créé un mappage spécifique entre les entités et forcé la table de références croisées et à la fois l'interrogation et la mise à jour fonctionne!

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<ListItem>() 
      .HasMany<Option>(s => s.Options) 
      .WithMany(c => c.ListItems) 
      .Map(cs => 
      { 
       cs.MapLeftKey("ListItem_Id"); 
       cs.MapRightKey("Option_Id"); 
       cs.ToTable("OptionListItems"); 
      }); 
    }