首先在EF代码中删除会导致导航属性设置为null并为空

Tho*_*mas 4 ef-code-first entity-framework-4.1

当我首先使用EF代码执行删除时,我发现了一些有趣的东西.我使用以下域模型:

public class User
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Playlist> Playlists { get; set; }
}

public class Playlist
{
    public virtual long Id { get; set; }
    public virtual string Title { get; set; }
    public virtual User User { get; set; }
    public virtual ICollection<Track> Tracks { get; set; }
}

public class Track
{
    public virtual long Id { get; set; }
    public virtual string Title { get; set; }
    public virtual Playlist Playlist { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

该模型使用以下配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().HasMany(x => x.Playlists).WithRequired(x => x.User).Map(x => x.MapKey("UserId"));
    modelBuilder.Entity<Playlist>().HasMany(x => x.Tracks).WithRequired(x => x.Playlist).Map(x => x.MapKey("PlaylistId"));
}
Run Code Online (Sandbox Code Playgroud)

我使用通用存储库:

public virtual void Delete(T entity)
{
    Database.Set<T>().Remove(entity);
}
Run Code Online (Sandbox Code Playgroud)

我也有一个看起来像的dto:

public class PlaylistDTO
{
    public PlaylistDTO(Playlist playlist)
    {
        Id = playlist.Id;
        Title = playlist.Title;
        User = playlist.User.Name;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的一项服务中,我尝试执行以下操作:

public PlaylistDTO Delete(long id)
{
    Playlist playlist = playlistRepository.GetById(id);
    playlistRepository.Delete(playlist);
    unitOfWork.Commit();

    return PlaylistDTO(playlist);
}
Run Code Online (Sandbox Code Playgroud)

此代码失败.当我通过调试器时,我发现了一些有趣的东西.我调用playlistRepository.Delete时,导航属性(User和Tracks)分别设置为null和empty.然而,播放列表会留在内存中.因此,当我将播放列表传递给DTO时,代码将在尝试访问playlist.User.Name时失败.我想将此数据传递给客户端以显示验证.

这种行为是否正确?这是设计的吗?

Lad*_*nka 7

这就是EF的工作原理.问题是您的Playlist表单实体图与其他关系和EF使用非常简单的规则来跟踪实体图:必须跟踪图中的所有实体 - 不能引用未跟踪的实体.我没有给你参考这条规则的描述,这只是我的观察,但我没有发现任何一个例外.

编辑:更新版本 - 我刚刚检查了内部实现,并且在调用Delete期间确实关系无关

那么代码中发生了什么.

  • 您已标记Playlist为已删除
  • EF将删除操作传递给执行修复的状态管理器 - 它将使所有关系为空
  • 您保存了对数据库的更改
  • 因为没有来自Playlist所有相关对象的级联删除仍未删除
  • 保存更改后,EF会在内部接受它们并将更改跟踪器设置为当前状态
  • 由于当前状态Playlist不存在(在数据库中删除),因此它与上下文分离
  • 分离已破坏实体图,EF通过修改两端的导航属性来修复它

负责归零的代码System.Data.Objects.EntityEntry.Delete(doFixup)(doFixup是真的) - 该类是内部的:

if (doFixup && (base.State != EntityState.Deleted))
{
    this.RelationshipManager.NullAllFKsInDependentsForWhichThisIsThePrincipal();
    this.NullAllForeignKeys();
    this.FixupRelationships();
}
Run Code Online (Sandbox Code Playgroud)

在您的方案中,这应该有简单的解决方法 - 在删除实体之前创建DTO.