如何更新Entity Framework 7中的多对多关系?

时间:2016-02-13 11:14:48

标签: asp.net entity-framework entity-framework-core

tl; dr:我有一些具有多对多关系的数据库。当我编辑其数据并调用SaveChanges()时,数据库中没有任何更改。

完整问题:

我遇到了一个非常奇怪的问题。我想更新多对多关系,但它并不想改变。

我的模特看起来像这样(我只发布了这个问题中很重要的部分):

public class Note
{
    public Note()
    {
        NoteTags = new HashSet<NoteTag>()
    }

    public int NoteId { get; set; }
    public virtual ICollection<NoteTag> NoteTags { get; set; }
    [...]
}

public class NoteTag
{
    public int NoteId { get; set; }
    public Note Note { get; set; }

    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

public class Tag
{
    public Tag()
    {
        NoteTags = new HashSet<NoteTag>();
    }

    public int TagId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<NoteTag> NoteTags { get; set; }
    [...]
}

我如何更新此数据库关系:

从数据库中获取当前状态Note

Note noteInDb = db.Notes.Include(x => x.NoteTags).ThenInclude(x => x.Tag).AsNoTracking().FirstOrDefault(x => x.NoteId == note.NoteId);

清除List<NoteTags>并添加一个新的:

noteInDb.NoteTags = new List<NoteTag>();
noteInDb = TagsToAddToTags(note);

TagsToAddToTags做了什么:它在数据库中找到合适的Tags并将其添加到List<>中,如下所示:

note.NoteTags.Add(new NoteTag { Tag = tagInDb });

然后我告诉数据库我已经修改了一些数据并保存了它:

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

当我将noteInDb变量保存到数据库中时,Note noteInDb2 = db.Notes.Include(x=>x.NoteTags).ThenInclude(x=>x.Tag).FirstOrDefault(x => x.NoteId == note.NoteId); 变量看起来就像我想要的那样。 很遗憾没有保存任何东西,当我查看数据库时,它看起来仍然和以前一样。

奇怪的是,当我在SaveChanges()之后写这行时:

noteInDb2

我可以看到NoteTag有9个NoteTag s(它之前有4个,我希望它有5个,所以这实际上是以前的内容和我想要的内容的总和加上)。但是当我去LINQPad看看它的真实情况时,它会显示我4个 <?php // Set the content-type header('Content-Type: image/png'); // Create the image $im = imagecreatetruecolor(400, 30); // Create some colors $white = imagecolorallocate($im, 255, 255, 255); $grey = imagecolorallocate($im, 128, 128, 128); $black = imagecolorallocate($im, 0, 0, 0); imagefilledrectangle($im, 0, 0, 399, 29, $white); // The text to draw $text = 'Testing...'; // Replace path by your own font path $font = 'arial.ttf'; // Add some shadow to the text imagettftext($im, 20, 0, 11, 21, $grey, $font, $text); // Add the text imagettftext($im, 20, 0, 10, 20, $black, $font, $text); // Using imagepng() results in clearer text compared with imagejpeg() imagepng($im); imagedestroy($im); ?> s(没有变化)。

我做错了什么?

2 个答案:

答案 0 :(得分:2)

您可以使用此扩展程序删除未选择的项目,并将新选择的项目添加到列表中:

sp

使用它看起来像这样:

public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
{
    db.Set<T>().RemoveRange(currentItems.Except(newItems, getKey));
    db.Set<T>().AddRange(newItems.Except(currentItems, getKey));
}

public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
{
    return items
        .GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
        .SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
        .Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
        .Select(t => t.t.item);
}

答案 1 :(得分:0)

我认为您需要移动代码。由于使用AsNoTracking检索数据,因此在将实体的状态设置为已修改之前,不会跟踪更改。因此,在调用TagsToAddToTags之前,请调用db.Entry(noteInDb).State = EntityState.Modified;