是否可以从收集中删除子项并解决SaveChanges上的问题?

时间:2012-06-14 12:47:03

标签: entity-framework entity-framework-4 persistence repository-pattern

我们正在使用Entity Framework Code First和Foreign Key关系。我们正在调查处理从应用程序中的实体ICollection中删除对象的方法。

当我们有一个具有子关系的实体时,我们可以使用Add方法将对象直接添加到他们的ICollection中。现在,当您使用删除时,您会收到错误

  

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

我理解这是因为集合上的Remove仅通过归零外键来删除关系。我们想在我们的实体中编写业务逻辑并允许删除。

所以从它的Repostiory中取出root实体,例如来自OrderRepository的Order然后调用该实体的一些特定方法,例如Order.AddOrderline(Orderline orderline)这会将OrderLine添加到订单virtual ICollection<OrderLine> OrderLines

但是我们无法编写像Order.CancelOrderline(int orderLineId)这样的代码,因为只需从ICollection中删除就会导致储蓄更改出错。

似乎没有办法通过操纵对象集合来实现这一点。显然我们可以直接从Context中删除。但是我想把它作为实体的一部分。我们可以在Entity Framework的SaveChanges事件中清除没有外键的某些实体吗?显然需要告诉EF如果它们具有空外键,可以删除哪些实体。

我们目前正在使用存储库模式,因此控制器无法访问上下文。我显然可以在Order存储库上使用OrderLine存储库或删除OrderLine方法。然而,只是想知道是否有可能在实体上编写代码而不引用持久性机制。

思考?我们这一切都错了吗?其他ORM是否允许您从Child Collections中删除?

2 个答案:

答案 0 :(得分:39)

我不知道以下是否适合您,但实体框架支持Identifying Relationships。在这种关系中,子实体(从属)与父(主体)的外键必须是子实体的(复合)主键的一部分。例如 - 使用DbContext数据注释 - 您的模型类必须如下所示:

public class Order
{
    [Key]
    public int OrderId { get; set; }

    public ICollection<OrderLine> OrderLines { get; set; }
}

public class OrderLine
{
    [Key, ForeignKey("Order"), Column(Order = 1)]
    public int OrderId { get; set; }

    [Key, Column(Order = 2)]
    public int OrderLineId { get; set; }

    public Order Order { get; set; }
}

如果需要,您可以将OrderLineId设为自动生成的身份。重要的是,Order的FK是PK的一部分。

像这样的代码......例如......

using (var ctx = new MyContext())
{
    var order = ctx.Orders.Include("OrderLines").Single(o => o.OrderId == 1);
    var orderLineToDelete = order.OrderLines
        .FirstOrDefault(ol => ol.OrderLineId == 5);
    if (orderLineToDelete != null)
        order.OrderLines.Remove(orderLineToDelete);

    ctx.SaveChanges();
}

...确实从数据库中删除 orderLineToDelete

“{em>识别和识别关系的注意事项”一节中的更多详细信息为here

答案 1 :(得分:2)

正如您所发现的那样,如果您只是从集合中删除实体,则实体会挂起附加到对象上下文并在您调用SaveChanges()时出错;我已经使用Domain Events来实现一种通过存储库从对象上下文中删除Entity的整洁方式。

我在答案to this question中详述了这种方法。