EF DbSet.Find() 返回分离实体

Posted

技术标签:

【中文标题】EF DbSet.Find() 返回分离实体【英文标题】:EF DbSet.Find() returns Detached Entity 【发布时间】:2015-04-17 14:50:03 【问题描述】:

我有一个非常简单的Entity,只有 4 个字段:姓名、州、城市和 ID 以及一些验证。

[Table("Places")]
public class Place : BindableBase, IDataErrorInfo

    private string name;
    private string city;
    private Estado state;
    private int id;

    [Required]
    [StringLength(500)]        
    public string Name
    
        get  return this.name; 
        set  SetProperty(ref name, value); 
    

    [Required]
    [StringLength(500)]
    public string City
    
        get  return this.city; 
        set  SetProperty(ref city, value); 
    

    [Required]        
    public State State
    
        get  return this.state; 
        set  SetProperty(ref state, value); 
    

    [Key]
    public int Id
    
        get  return this.id; 
        set  SetProperty(ref id, value); 
    

    [NotMapped]
    public bool IsValid
    
        get 
        
            return Validator.TryValidateObject(this, new ValidationContext(this), new Collection<ValidationResult>(), true);
        
    

    #region IDataErrorInfo Members
    /// <summary>
    /// IDataErrorInfo Interface Error Message for the object.
    /// </summary>
    [NotMapped]
    public string Error
    
        get  throw new NotImplementedException(); 
    

    public string this[string propertyName]
    
        get 
        
            var context = new ValidationContext(this)
            
                MemberName = propertyName
            ;

            var results = new Collection<ValidationResult>();
            bool isValid = Validator.TryValidateObject(this, context, results, true);

            if (!isValid)
            
                ValidationResult result = results.SingleOrDefault(p =>
                                                                  p.MemberNames.Any(memberName =>
                                                                                    memberName == propertyName));

                return result == null ? null : result.ErrorMessage;
            

            return null; 
        
    
    #endregion

我可以将它添加到数据库中,但是一旦我尝试更新它,我就会得到一个异常。

我正在使用:

public void UpdatePlace(Place place)

    var entity = context.Places.Find(place.Id);

    if (entity == null)
    
        throw new InvalidOperationException("Place not found.");
    

    context.Entry(place).CurrentValues.SetValues(place);
    context.SaveChanges();

当我到达时

context.Entry(place).CurrentValues.SetValues(place);

我得到一个例外:

System.InvalidOperationException

“不能为类型的实体调用成员'CurrentValues' 'Place' 因为实体在上下文中不存在。 要将实体添加到上下文中,请调用的 Add 或 Attach 方法 数据库集。”

context.Entry 告诉我该实体确实是分离的

但是DbSet.Find() 方法的文档清楚地表明Find() 应该返回一个附加实体,以防在数据库中找到一个实体:

查找具有给定主键值的实体。如果上下文中存在具有给定主键值的实体,则立即返回它而不向存储区发出请求。否则,将向存储请求具有给定主键值的实体,并且此实体(如果找到)将附加到上下文并返回。如果在上下文或存储中没有找到实体,则返回 null。

所以当我尝试获取CurrentValues 时,由于实体已分离,它会抛出Exception... 但据我所知,应该有一个附加的实体,或者为null,而不是其他任何东西。 ...

我在网上找不到有关此错误的任何信息,我使用 SQL CE 4.0 作为数据库,有人知道发生了什么吗?

我认为每次从Find 获取实体时,我都可以只Attach,但我仍然想了解我的软件发生了什么,因为这不应该发生。

【问题讨论】:

【参考方案1】:

我认为你应该将这一行改为:

  context.Entry(entity).CurrentValues.SetValues(place);

【讨论】:

好吧...现在感觉自己傻了哈哈哈,这段代码是从教程中得到的,本来应该多注意复制+粘贴的,教程完全错了,我会通知作者。非常感谢 ErikEJ! youtube.com/watch?v=7SwgqLJCLI8 代码显示在视频的 6:30。 实际上是 4:00 分钟。 补充一点,他确实进行了单元测试,所以显然这段代码是“可信的”....我想这会成为关于测试的一个很好的教训......

以上是关于EF DbSet.Find() 返回分离实体的主要内容,如果未能解决你的问题,请参考以下文章

从零开始搭建前后端分离的NetCore(EF Core CodeFirst+Au)+Vue的项目框架之三统一返回数据

EF6 无法将分离的实体附加到上下文

EF架构~FluentValidation实体检验与实体分离了

TeamCity 中的 EF6 和 MSTest:实体框架提供程序必须从此类继承,并且“实例”成员必须返回单例实例

EF执行savechanges失败然后直接返回页面的处理办法

如何更新 EF CF 中的实体对象(分离)?