gpt4 book ai didi

asp.net-core - EF7 中导航属性的更新未保存

转载 作者:行者123 更新时间:2023-12-02 03:22:15 25 4
gpt4 key购买 nike

我有简单的模型:

public class Post
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { set; get; }
//non-important properties stripped, to focus on problem
public virtual Resource Resource { set; get; }

public virtual ICollection<Tag> Tags { set; get; }
}
public class Resource
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { set; get; }

[Url]
public string Url { set; get; }
}

和 DbContext(我在此项目中使用 ASP.NET 标识,如果相关的话):

public class DbContext : IdentityDbContext<User>
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var postEntity = modelBuilder.Entity<Post>();
postEntity.Reference(p => p.Resource).InverseCollection(); //no navigation property on Resource side
postEntity.Collection(p => p.Tags).InverseReference(tag => tag.Post);
postEntity.ToTable("Posts");

var resourceEntity = modelBuilder.Entity<Resource>();
resourceEntity.ToTable("Resources");

var tagEntity = modelBuilder.Entity<Tag>();
tagEntity.Reference(t => t.Post).InverseCollection(p => p.Tags).Required(false);
tagEntity.ToTable("Tags");
}
}

迁移后 (SQL Server),数据库表看起来像预期的那样 - Post 表具有指向 ResourceId 的外键。

当我附加 post.Resource(已创建的资源)时,创建 Post 的工作正常。

当我想替换 post.Resource 时出现问题通过替换,我的意思是选择一个已经存在的资源并将其分配给发布。

var resource2 = Database.Resources.First(r=>r.Url == "xyz");

我试过:

  1. post.Resource = resource2; Database.Entry(post).State = EntityState.Modified;

  2. Database.Entry(post).Property(p => p.Resource).CurrentValue = resource2;

  3. post.Resource = null;

它们也有不同的组合,但它们都不起作用。调用 await SaveChangesAsync(); 并在数据库中查找后 - 没有任何变化。如何正确执行替换(更新外键)​​?

//更新 14.09.2015问题是由额外的选择引起的,执行更新一对多关系。完整代码:

        var Database new DbContext();
var resource2 = Database.Resources.First(r=>r.Url == "xyz");
var oldAssignedTags = Database.Posts.Include(p=>p.Tags).FirstOrDefault(p => p.Id == post.Id).Tags;
var tags = newTags as List<Tag> ?? newTags.ToList();
//TagComparer is irrelevant here
var toRemove = oldAssignedTags.Except(tags, TagComparer);
var toAdd = tags.Except(oldAssignedTags, TagComparer);

foreach (var tag in toRemove)
{
Database.Entry(tag).State = EntityState.Deleted; //Database.Tags.Remove(tag);
}

foreach (var tag in toAdd)
{
tag.Post = post;
post.Tags.Add(tag);
}

post.Resource = resource2;
await Database.SaveChangesAsync();

最佳答案

我认为这可能与 Eager Loading 有关,但是无论是否使用 AspNet.Identity,我都无法重现您的问题。运行以下代码会导致资源始终被更新。使用 EntityFramework 7.0.0-beta7

代码

static void Main(string[] args)
{
Init();
WithEagerLoading();
CleanUp();

Init();
WithoutEagerLoading();
CleanUp();
}

private static void WithoutEagerLoading()
{
var db = new MyContext();
var post = db.Posts.First(); // no eager loading of child
post.Resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
db.SaveChanges();

Console.WriteLine($"2nd Resource.Id: {new MyContext().Posts.Include(p => p.Resource).First().Resource.Id}");
}

private static void WithEagerLoading()
{
var db = new MyContext();
var post = db.Posts
.Include(p => p.Resource) // eager loading
.First();
post.Resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
db.SaveChanges();

Console.WriteLine($"2nd Resource.Id: {new MyContext().Posts.Include(p => p.Resource).First().Resource.Id}");
}

private static void CleanUp()
{
var db = new MyContext();
db.Posts.RemoveRange(db.Posts);
db.Resources.RemoveRange(db.Resources);
db.SaveChanges();
}

private static void Init()
{
var db = new MyContext();
var resource = new Resource { Url = "http://atqu.in" };
var resource2 = new Resource { Url = "http://trend.atqu.in" };
var post = new Post { Resource = resource };
db.Add(post);
db.Add(resource);
db.Add(resource2);
db.SaveChanges();

db = new MyContext();
post = db.Posts.Include(p => p.Resource).First();
resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
Console.WriteLine($"1st Resource.Id: {post.Resource.Id}");
}

结果

1st Resource.Id: 0f4d222b-4184-4a4e-01d1-08d2bc9cea9b
2nd Resource.Id: 00ccae9c-f0da-43e6-01d2-08d2bc9cea9b
1st Resource.Id: 749f08f0-2426-4043-01d3-08d2bc9cea9b
2nd Resource.Id: 2e83b512-e8bd-4583-01d4-08d2bc9cea9b

编辑 16/9

已编辑问题代码中的问题是因为您在检索到 post 之后实例化了 Databasepost 未附加到 Database 实例,因此当您将 Resource 附加到它并调用 SaveChangesAsync 时什么都不做,因为那时 post 与你保存的 Database 无关。这就是为什么您再次选择 post post 的解决方法(在实例化之后)导致它被修复 - 因为 post 的实例被附加了。如果您不想再次选择 post,您应该使用相同的 DbContext 实例来完成您最初用于检索 post 的上述工作>.

关于asp.net-core - EF7 中导航属性的更新未保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32543448/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com