3

我在 EF4 CTP5 项目上使用 POCO 类,但在删除子属性时遇到问题。这是我的例子(希望不会太长)。

Tour Class的相关部分

public partial class Tour
{
  public Guid TourId { get; private set; }
  protected virtual List<Agent> _agents { get; set; }

  public void AddAgent(Agent agent)
  {
    _agents.Add(agent);
  }

  public void RemoveAgent(Guid agentId)
  {
    var a = Agents.Single(x => x.AgentId == agentId);
    _agents.Remove(Agents.Single(x => x.AgentId == agentId));
  }
}

命令处理程序

public class DeleteAgentCommandHandler : ICommandHandler<DeleteAgentCommand>
{
  private readonly IRepository<Core.Domain.Tour> _repository;
  private readonly IUnitOfWork _unitOfWork;

  public DeleteAgentCommandHandler(
      IRepository<Core.Domain.Tour> repository, 
      IUnitOfWork unitOfWork
    )
  {
    _repository = repository;
    _unitOfWork = unitOfWork;
  }

  public void Receive(DeleteAgentCommand command)
  {
    var tour = _repository.GetById(command.TourId);
    tour.RemoveAgent(command.AgentId);

    // The following line just ends up calling
    // DbContext.SaveChanges(); on the current context.

    _unitOfWork.Commit();
  }
}

这是我在 UnitOfWork 调用时遇到的错误DbContext.SaveChanges()

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

发生这种情况是因为 EF 不会仅仅因为它已从我的 Tour 类的 Agents 集合中删除而自动从数据库中删除代理实体。

我需要显式调用dbContext.Agents.DeleteObject(a);,但我的问题是,我无法从我的 POCO 中访问 dbContext。

有没有办法处理这种情况?

4

2 回答 2

1

对于您当前的架构,恐怕您需要为您DeleteAgentCommandHandler提供第二个存储库(IRepository<Core.Domain.Agent>我猜是 ),然后Delete(command.AgentId)在第二个存储库上调用类似的东西。

或者您可以将您扩展IUnitOfWork为存储库工厂,因此该接口将获得一个额外的方法,例如T CreateRepository<T>()允许您从工作单元中提取通用存储库的任何实例。(然后你只需要注入IUnitOfWork,DeleteAgentCommandHandler而不是存储库了。)

或者远离业务/UI 层中的通用存储库。如果Agent完全依赖于Tour它,则根本不需要存储库。非泛型ITourRepository可以有方法来适当地处理从数据库层中的游览中删除代理的情况。

于 2011-03-17T20:26:25.803 回答
0

这看起来确实应该起作用。我发现这篇文章表明正在研究此功能以用于未来版本:

http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/58a31f34-9d2c-498d-aff3-fc96988a3ddc/

我还发现了另一篇文章(在某个地方 - 不幸的是我丢失了它),它建议在您的 DbContext OnModelCreating 方法中将父实体的密钥添加到子实体,如下所示:

modelBuilder.Entity<Agent>()
.HasKey(AgentId)
.HasKey(TourId);

目前,这会在运行时使用代码优先引发异常,尽管我在使用 EDMX 文件时通过破解 XAML 以在存储数据模型和概念数据模型中包含父键来实现此功能。我认为这种行为差异是因为在 EDMX 文件的情况下,EF 相信它保存的存储元数据是准确的,而代码先检查数据库以查看其模型是否匹配。

尽管我还没有尝试过,但另一种可能可行的方法是将父键作为复合键包含在子表中,以便代码优先。显然,更改数据库或破解 XAML 都不太理想,充其量只是解决方法。

于 2011-06-01T12:41:29.543 回答