开发者

Unable to delete child entities from a POCO using Unit Of Work pattern

开发者 https://www.devze.com 2023-02-17 17:43 出处:网络
I am using POCO classes on an EF4 CTP5 project and I am having trouble deleting child properties. Here\'s my example (hopefully not too long).

I am using POCO classes on an EF4 CTP5 project and I am having trouble deleting child properties. Here's my example (hopefully not too long).

Relevant Portions of the 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));
  }
}

Command Handler

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();
  }
}

Here's the error that I get when my UnitOfWork calls DbContext.SaveChanges()

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

This is happening because EF wont just automatically delete the an Agent entity from the database just because it has been removed from the Agents collection in my Tour 开发者_开发问答class.

I need to explicitly call dbContext.Agents.DeleteObject(a);, but my problem is, I don't have access to the dbContext from within my POCO.

Is there any way to handle this scenario?


With your current architecture I am afraid you need to feed your DeleteAgentCommandHandler with a second repository (IRepository<Core.Domain.Agent>, I guess) and then call something like Delete(command.AgentId) on that second repository.

Or you could extend your IUnitOfWork to be a factory of repositories, so the interface would get an additional method like T CreateRepository<T>() which allows you to pull any instance of your generic repository from the unit of work. (Then you only need to inject IUnitOfWork into the DeleteAgentCommandHandler, and not the repositories anymore.)

Or stay away from generic repositories in your business/UI layer. If Agent is completely dependent on Tour it doesn't need to have a repository at all. A non-generic ITourRepository could have methods to handle the case of removing an agent from a tour in the database layer appropriately.


This does seem like something that should work. I've found this post which suggests this feature is being investigated for future versions:

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

I've also found another post (somewhere - unfortunately I lost it) which suggested adding the parent entity's key to the child entity in your DbContext OnModelCreating method like this:

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

Currently this throws an exception at runtime using code-first, although I have got this working when using an EDMX file by hacking the XAML to include the parent key in the store data model as well as the conceptual data model. I think this difference in behaviour is because in the case of the EDMX file, EF trusts that the store metadata it holds is accurate, whereas code-first checks the database to see whether it's model matches.

Another way which may work although I haven't yet tried it yet, is to include the parent key as a compound key in the child table so that code-first is happy. Obviously changing the database or hacking the XAML are both less than ideal and workarounds at best.

0

精彩评论

暂无评论...
验证码 换一张
取 消