首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法更新实体框架虚拟列表对象

无法更新实体框架虚拟列表对象
EN

Stack Overflow用户
提问于 2015-01-08 14:13:15
回答 2查看 1.1K关注 0票数 1

我将尝试简单地解释我的实体框架模型。我有一个用户对象,它的集合为零或多个UserInterest对象。每个用户兴趣对象只有三个属性,即唯一ID、用户Id和描述。

每当用户更新用户对象时,它也应该更新相关的UserInterest对象,但是由于这些对象是免费的(即不是允许兴趣列表的一部分),所以我希望用户将一个类型为"string“的列表传递给他们感兴趣的名称的all方法。理想情况下,代码将查看用户现有的兴趣列表,删除任何不再相关的内容,并添加新的兴趣列表,并保留已经存在的兴趣列表。

我的对象模型定义

代码语言:javascript
复制
[Table("User")]
public class DbUser {
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public virtual IList<DbUserInterest> Interests { get; set; }
}

[Table("UserInterest")]
public class DbUserInterest : IEntityComparable<DbUserInterest>
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    public virtual DbUser User { get; set; }
    public int? UserId { get; set; }
}

上下文Fluent映射

代码语言:javascript
复制
modelBuilder.Entity<DbUser>()
    .HasKey(u => u.UserId);
modelBuilder.Entity<DbUser>()
    .Property(u => u.UserId)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<DbUser>()
    .HasMany(u => u.Interests)
    .WithRequired(p => p.User)
    .WillCascadeOnDelete(true);

modelBuilder.Entity<DbUserInterest>()
    .HasKey(p => p.Id);
modelBuilder.Entity<DbUserInterest>()
    .Property(p => p.Id)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<DbUserInterest>()
    .HasRequired(p => p.User)
    .WithMany(u => u.Interests)
    .WillCascadeOnDelete(true);

最后,我的webmethod代码和存储库方法进行了更新。

代码语言:javascript
复制
public UpdateUserProfileDetailsResponse UpdateUserProfileDetails(UpdateUserProfileDetailsRequest request)
{
    try
    {
        var dbItem = _userDataRepository.GetItem(request.Header.UserId);

        dbItem.Interests.Clear();
        foreach (var dbInterest in request.UserInterests)
            dbItem.Interests.Add(new DbUserInterest { Name = dbInterest, UserId = dbItem.UserId});

        _userDataRepository.UpdateItem(dbItem);
        _userDataRepository.Save();
    }
    catch (Exception ex)
    {
    }
}

public override bool UpdateItem(DbUser item)
{
    var dbItem = GetItem(item.UserId);
    if (dbItem == null)
        throw new DataRepositoryException("User not found to update", "UserDataRepository.UpdateItem");

    var dbInterests = Work.Context.UserInterests.Where(b => b.UserId == item.UserId).ToList();
    var interestsToRemove = (from interest in dbInterests let found = item.Interests.Any(p => p.IsSame(interest)) where !found select interest).ToList();
    var interestsToAdd = (from interest in item.Interests let found = dbInterests.Any(p => p.IsSame(interest)) where !found select interest).ToList();

    foreach (var interest in interestsToRemove)
        Work.Context.UserInterests.Remove(interest);

    foreach (var interest in interestsToAdd)
    {
        interest.UserId = item.UserId;
        Work.Context.UserInterests.Add(interest);
    }                

    Work.Context.Entry(dbItem).State = EntityState.Modified;
    return Work.Context.Entry(dbItem).GetValidationResult().IsValid;
}

当我运行这个程序时,在Repository.Save()行中我得到了异常

代码语言:javascript
复制
Assert.IsTrue failed. An unexpected error occurred: An error occurred while updating the entries. See the inner exception for details.

但有趣的是,在get方法中,如果我注释掉行dbItem.Interests.Clear();,它不会抛出一个错误,当然,您会得到重复或额外的项目,因为它认为所有内容都需要添加。但是,删除这一行是使代码不出错的唯一方法。

在此之前,我将兴趣对象的UserId属性设置为非空对象,然后错误略有不同,您不能更改不可空的外键实体的关系,这就是为什么我将属性更改为可空但仍然不为空。

有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-08 14:51:57

您不能只清除集合,然后尝试重新构建它。EF不是那样工作的。DbContext在其变更跟踪器中跟踪从数据库中带回的所有对象。当然,这样做会造成重复,因为EF看到它们根本不在变更跟踪器中,所以它们必须是全新的对象,因此需要添加到数据库中。

您需要在UpdateUserProfileDetails方法中执行添加/删除逻辑,或者必须找到将request.UserInterests传递到UpdateItem方法的方法。因为您需要调整现有实体,而不是在请求中找到的实体( EF认为这些实体是新的)。

票数 1
EN

Stack Overflow用户

发布于 2015-01-08 14:53:54

你可以用这种方式移除

代码语言:javascript
复制
dbItem.Interests.Clear();

然后

代码语言:javascript
复制
    foreach (var dbInterest in request.UserInterests){
      if(dbItem.Interests.Any()){
        if (dbItem.Interests.Count(i=> i.Name==dbInterest && i.UserId==dbItem.UserId) == 0){
          dbItem.Interests.Add(new DbUserInterest { Name = dbInterest, UserId = dbItem.UserId});
        }
      }
   }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27842157

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档