【问题标题】:The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable.操作失败:无法更改关系,因为一个或多个外键属性不可为空。
【发布时间】:2016-06-29 16:58:16
【问题描述】:

此问题可能与其他类似问题相似。但我建议您将问题阅读到最后,然后确定它是否与某些帖子重复?????

我的数据库中有 6 个表,如下所示:

我已经在所有表中插入了一些记录。

现在,我正在尝试更新订单。

起初,我只是尝试更新顺序如下:

CurrentOrder.UpdateOrder(Order);

OrderClient 中的 UpdateOrder 方法如下所示:

public Order UpdateOrder(Order Order)
{
    IOrderRepository OrderRepository = _DataRepositoryFactory.GetDataRepository<IOrderRepository>();

    Order updatedEntity = null;

    if (Order.OrderId == 0)
    {
        updatedEntity = OrderRepository.Add(Order);
    }
    else
    {
        updatedEntity = OrderRepository.Update(Order);
    }

    return updatedEntity;

}

在 OrderRepository 中:

protected override Order UpdateEntity(RateDifferenceContext entityContext, Order entity)
{
    return (from e in entityContext.OrderSet
            where e.OrderId == entity.OrderId
            select e).FirstOrDefault();
}

然后在 DataRepositoryBase 类中我使用以下方法:

public T Update(T entity)
{
    using (U entityContext = new U())
    {
        T existingEntity = UpdateEntity(entityContext, entity);
        SimpleMapper.PropertyMap(entity, existingEntity);
        entityContext.SaveChanges();
        return existingEntity;
    }
}

此时我收到一条错误消息:

违反了多重性约束。关系“…”的角色“…”的重数为 1 或 0..1

所以,我认为我需要删除所有相关表中特定于此顺序的记录。所以,我尝试了以下代码:

using (var xaction = new TransactionScope())
{
    foreach (OrderItemDetail orderItemDetail in OrderItemDetailClient.GetAllOrderItemDetails().Where(x => x.OrderId == NewOrder.OrderId))
    {
        OrderItemDetailClient.DeleteOrderItemDetail(orderItemDetail);
    }

    foreach (Dispatch dispatch in DispatchClient.GetAllDispatches().Where(x => x.OrderId == NewOrder.OrderId))
    {
        foreach (DispatchItemDetail dispatchItemDetail in DispatchItemDetailClient.GetAllDispatchItemDetails().Where(x => x.InvoiceId == dispatch.InvoiceId))
        {
            DispatchItemDetailClient.DeleteDispatchItemDetail(dispatchItemDetail);
        }

        DispatchClient.DeleteDispatch(dispatch);
    }

    OrderClient.UpdateOrder(NewOrder);

    xaction.Complete();
}

现在,我收到另一个错误消息:

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

我在最后一个代码块的下面提到的行中收到此错误:

DispatchClient.DeleteDispatch(dispatch);

【问题讨论】:

    标签: c# entity-framework linq


    【解决方案1】:

    你有两个不同的问题。我们没有足够的细节来为您提供具体的修复,但由于这些都是非常常见的 EF“陷阱”,我相信了解正在发生的事情是很有价值的。

    第一个错误:

    违反了多重性约束。关系“……”的角色“……” 重数为 1 或 0..1

    这意味着您的外键属性不匹配。在 EF 中,您经常会遇到在模型中以多种方式表示相同 SQL 关系的情况。

    例如,您的 Order 类可能有一个 OrderItemDetails 集合(使用 OrderItemDetail.OrderId 填充)。您的 OrderItemDetail 也可能有一个 Order 属性,该属性使用相同的外键填充。如果这两个属性都标记为已更改但新值不匹配,则 EF 不知道要保存到 OrderItemdetail.OrderId 字段的新值。在那种情况下,它会抛出这个异常。如果 OrderItemDetail 有 Order 属性和 OrderId 属性,也会出现同样的问题。

    为避免此问题,您必须非常小心修改哪些属性。使用属性映射器可能很危险,因为它们可能“意外”修改错误的属性并导致很多类似的问题。我们需要看看 SimpleMapper 是如何工作的,或者如何配置映射以真正解决问题。

    第二个错误:

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

    此错误通常意味着您并未真正删除对象。您正在从关系集合中删除对象,它只是将外键设置为 null。

    继续上面的例子,如果你调用 myOrder.OrderItemDetails.Remove(detail) 然后调用 SaveChanges,你可能认为它只会从数据库中删除 OrderItemDetail 记录,但这并不是你告诉它做的。您已将其从 myOrder 关联的订单项详细信息列表中删除。为了实现这一点,EF 生成一个 UPDATE 语句,将 OrderId 列设置为空。如果没有来自 DeleteDispatch 方法的模型和代码的更多详细信息,很难确切知道问题出在哪里,但异常意味着它试图将该外键属性设置为 null 并且由于它不可为空而失败。

    “修复”是直接从 Context 集合中删除项目,而不是相关的项目集合。 IE。而不是 myOrder.OrderItemDetails.Remove,您应该调用 context.OrderItemDetails.Remove。这会真正删除记录。

    【讨论】:

    • 感谢您的精彩解释。我得到了答案。
    猜你喜欢
    • 1970-01-01
    • 2015-12-16
    • 2013-10-19
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多