Добавление элемента со связями «многие ко многим» в платформе - PullRequest
9 голосов
/ 26 июля 2011

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

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

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

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

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

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.Tags.Add ().

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

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

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

Ответы [ 2 ]

17 голосов
/ 26 июля 2011

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

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();
}
0 голосов
/ 26 июля 2011

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

Используйте что-то вроде

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/

...