2011-07-26 11 views
8

estoy recibiendo un error de violación de clave principal cuando intento añadir un elemento con una relación de muchos a muchos:Adición de artículo con muchos-a-muchos relación en Entity Framework

Tengo dos clases - los artículos y etiquetas que tienen una relación de muchos a muchos:

public class Article 
{ 
    public int ID { get; set; } 
    public string Text { get; set; } 
    public ICollection<Tag> Tags { get; set; } 
} 

public class Tag 
{ 
    [Key] 
    public string UrlSlug { get; set; } 
    public string Name { get; set; } 
    public ICollection<Article> Articles{ get; set; } 
} 

al agregar un nuevo artículo que permiten al usuario introducir cualquier etiqueta y luego me quieren crear una nueva etiqueta si la etiqueta no ha sido creada todavía en la base de datos o agregue la etiqueta a la colección Etiquetas del objeto Artículo si la etiqueta ya existe.

Por lo tanto, cuando estoy creando el nuevo artículo objeto que llama a la función a continuación:

public static Tag GetOrLoadTag(String tagStr) 
     { 
      string tagUrl = Tag.CreateTagUrl(tagStr); 
      var db = new SnippetContext(); 
      var tagFromDb = from tagdummy in db.Tags.Include(x => x.Articles) 
          where tagdummy.UrlSlug == tagUrl 
          select tagdummy; 
      if (tagFromDb.FirstOrDefault() != null) 
      { return tagFromDb.FirstOrDefault(); } 
      else 
      { 
       //create and send back a new Tag 
      } 

     } 

Esta función básicamente comprueba si hay una etiqueta disponible en la base de datos y si es así devuelve esa etiqueta que se añade a continuación a la colección Tag del objeto Article utilizando article.Tags.Add().

Sin embargo, cuando intento guardar esta utilizando el código de abajo consigo una Violación de error de restricción PRIMARY KEY

db.Entry(article).State = EntityState.Modified; 
db.SaveChanges(); 

no puedo averiguar cómo debería ir sobre apenas crear una relación entre el artículo y la etiqueta ya existente.

+0

¿Puede proporcionarnos más detalles y el código completo? –

Respuesta

14

uso de la misma instancia de contexto para todo el proceso de su operación y su vida será mucho más fácil:

using (var ctx = new MyContext()) 
{ 
    Article article = ctx.Articles.Single(a => a.Id == articleId); 
    Tag tag = ctx.Tags.SingleOrDefault(t => t.UrlSlug == tagUrl); 
    if (tag == null) 
    { 
     tag = new Tag() { ... } 
     ctx.Tags.AddObject(tag); 
    } 

    article.Tags.Add(tag); 
    ctx.SaveChanges(); 
} 

Si no desea cargar el artículo desde la base de datos (esa consulta es redundante si sabe que existe el artículo) puede usar:

using (var ctx = new MyContext()) 
{ 
    Article article = new Article() { Id = articleId }; 
    ctx.Articles.Attach(article); 

    Tag tag = ctx.Tags.SingleOrDefalut(t => t.UrlSlug == tagUrl); 
    if (tag == null) 
    { 
     tag = new Tag() { ... } 
     ctx.Tags.AddObject(tag); 
    } 

    article.Tags.Add(tag); 
    ctx.SaveChanges(); 
} 
+0

Gracias hizo el truco. Supongo que mucha gente se tropieza con Entity Framework al usar un Contexto diferente. El problema es que hacer todo en la misma operación va en contra de cómo normalmente programamos un DAL con diferentes operaciones. La mejor apuesta parece estar pasando el contexto como un parámetro de referencia. – Judo

+0

@Judo, es por eso que le pregunté "Asegúrese de que cuando está recuperando la etiqueta de db en el código, está utilizando el mismo contexto de datos que está utilizando al llamar a SaveChanges" –

+0

Solo para tener en cuenta, ya que tropecé aquí - si '** está abstrayendo el contexto detrás de un patrón de repositorio ** asegúrese de que puede ** compartir el contexto mediante inyección/fábrica ** correctamente. Pero si comparte el contexto a través de los métodos/ámbitos, podría encontrarse con problemas en los que ** commits fallidos rompen subsiguientes commits no relacionados ** - algo como este método de "deshacer" podría ayudar? http://rundevrun.blogspot.com/2012/06/entity-framework-removing-failed.html – drzaus

0

¿Cómo se crean nuevas etiquetas? Y cómo adjuntas la entidad existente o creada al artículo.

usar algo como

Article a = new Article(...); 
a.tags.add(GetOrLoadTag("some tag")); 

Lee este artículo http://thedatafarm.com/blog/data-access/inserting-many-to-many-relationships-in-ef-with-or-without-a-join-entity/

+0

Si existe una etiqueta, simplemente la agrego usando article.Tag.Add (existingTag). Pero cuando intento guardarlo arroja el error de violación de la clave primaria. – Judo

+0

Cuando se trata de una etiqueta existente, debe informar al marco que se trata de una entidad existante. El marco está tratando de insertar la entidad nuevamente. Y asegúrese de haber configurado la columna de identidad en la clave principal. –

+0

Ok, entonces, ¿cómo dejo que el framework sepa que es una entidad existente? – Judo

Cuestiones relacionadas