Добавление элемента с отношением "многие ко многим" в Entity Framework

Я получаю ошибку нарушения первичного ключа, когда пытаюсь добавить элемент с отношением "многие ко многим":

у меня есть два класса - статьи и теги, которые имеют многие-ко-многим отношения :

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; }
}

когда я добавляю новую статью, я разрешаю пользователю вводить любые теги, а затем я хочу создать новый тег, если тег еще не создан в базе данных или добавить тег в коллекцию тегов объекта статьи, если тег уже существует.

поэтому, когда я создаю новый объект статьи, я вызываю следующую функцию:

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
            }

        }

эта функция в основном проверяет, есть ли доступный тег в базе данных, и если да, то возвращает этот тег, который затем добавляется в коллекцию тегов объекта Article с помощью article.Метить.Добавлять.)(

однако, когда я пытаюсь сохранить это, используя приведенный ниже код, я получаю нарушение ошибки ограничения первичного ключа

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

Я не могу понять, как я следует просто создать связь между статьей и уже существующим тегом.

2 ответов


используйте один и тот же экземпляр контекста для всей обработки вашей операции, и ваша жизнь будет намного проще:

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();
}

Если вы не хотите загружать статью из базы данных (этот запрос является избыточным, если вы знаете, что статья существует), вы можете использовать:

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();
}

Как вы создаете новые теги? И как вы присоединяете существующий или созданный объект к статье.

использовать что-то вроде

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

прочитайте эту статью http://thedatafarm.com/blog/data-access/inserting-many-to-many-relationships-in-ef-with-or-without-a-join-entity/