如何在后面的代码中设置导航属性的值?

本文关键字:属性 导航 设置 在后面 代码 | 更新日期: 2023-09-27 18:06:26

我有一个名为Cost的实体,它具有CostType的必需属性

Cost类有一个GetNew()方法,它设置所有的成本默认值:

public static GetNew()
{
    Cost cost = new Cost ();
    foo.CostType = Lists.CostTypes.FirstOrDefault();
    // Other Default Values
    return foo;
}

Lists.CostTypes是一个静态列表,在启动时从EF中提取,并在组合框中使用

GetNew()方法中首先设置CostType后,我在代码中设置CostType有问题。

例如,下面的代码读取excel文件,并根据excel文件中的列设置默认类型,如果找不到匹配的 ,则设置为空。
Cost cost = Cost.GetNew();
cost.CostType = Lists.CostTypes.FirstOrDefault(t => t.Name == row[0].ToString());

我的问题是,在保存操作期间,我得到以下错误:

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

我的添加操作如下所示:

public static void AddObject(EntityObject obj, string entitySetName)
{
    context.AddObject(entitySetName, obj);
    context.SaveChanges();
}
  • 如果我删除一行代码,手动设置成本时,它读取excel文件,保存工作正常。
  • 如果我更改代码行以读取列表。成本[2],它节省精细。
  • 如果我删除GetNew()中设置默认值的代码行,我得到一个错误告诉我,我违反了CostTypes的PK规则,这意味着它试图插入成本类型。
  • 将ComboBox显示类型更改为其他类型仍然会给出相同的错误。
  • 从excel文件加载成本后,当我更改类型并尝试保存时,我的常规添加/编辑表单会抛出相同的错误。如果我不加载excel文件,他们工作得很好。

我还在学习实体框架,但到目前为止,它一直只是一个挫折和头痛的使用。有人知道我的问题是什么,我怎么能解决它吗?

编辑

这是Slauma请求的信息。我保持简单,排除不相关的对象

  • Costs在一个表中,CostTypes在另一个表中。在数据库中,Costs.TypeId列不允许为空,是CostTypes的外键。Id字段是自动生成的

  • 我的EF模型只是一个添加了两个数据库表的通用模型。我对它所做的唯一改变是重命名一些字段,并删除CostTypes.Costs导航属性。

  • 导入的Excel文件映射大多数成本到他们匹配的CostType.Name,但是有可能Excel文件中的字符串不匹配CostType,所以Lists.CostTypes.FirstOrDefault(t => t.Name == row[0].ToString()) can assign a NULL value to the成本。输入property. That doesn't seem to be a problem though, because the form still comes up with the list of costs and their default selected items. Item's with a NULL CostType do not have an item selected in the CostType ComboBox ',触发一个验证错误,必须在保存之前纠正。

加载CostType列表的代码为
public static List<T> GetList<T>(string sortProperty)
    where T : EntityObject
{
    using (var context = new TContext())
    {
        return ApplyOrder<T>(context.CreateObjectSet<T>(), sortProperty, "OrderBy").ToList();
    }
}

ApplyOrder代码可以在这里找到。

调用GetList方法
public static class Lists
{
    public static List<CostType> CostTypes { get; private set; }
    static Lists()
    {
        CostTypes = DAL<CostEntities>.GetList<CostType>("Name");
    }
}

如何在后面的代码中设置导航属性的值?

我算出来了....它是几种不同事物的混合

创建新的Cost并设置Type是在向共享数据上下文添加成本。如果该成本没有包含在要保存的成本列表中,或者验证错误失败,或者用户取消了导入对话框,则成本仍然存在于context.ObjectStateManager._addedObjects中,即使我从未调用AddObjectAttachObject。一旦我意识到,我开始调用DeleteObject的成本是不会被保存的,它清除了我得到的第一个错误。

我得到的第二个错误(重复的PK)是因为我在循环我的新成本并调用AddObjectSaveChanges。由于将Cost.Type设置为附加的CostType会自动将我的成本添加到上下文中,因此要保存的第一个成本实际上是将所有新成本添加到数据库中,而第二个成本是试图调用AddObject/SaveChanges, EF将其视为已经存在的对象

这不是一个真正令人满意的答案,而是基于你在问题中的信息和对你的问题的评论的猜测和开放问题的混合:

  • 首先:您的列表Lists.CostTypes显然包含从您稍后添加和保存新对象的上下文中分离的实体。因为你有一个using块:using (var context = new TContext()),你在另一个上下文中检索你的CostType实体。

  • 要告诉EF这些CostType实体已经存在于数据库中,您必须实体附加到您保存更改的第二个上下文(context.CostTypes.Attach(costType))中(或在您检索列表的方法中使用相同的上下文)。我在你的代码中没有看到这样做。(CostType是导航引用属性,不是外键属性,对吧?)

  • 另一方面,当CostType实体没有附加时,您应该在数据库中获得重复的CostTypes,因为当您为Cost实体调用AddObject时,EF会将它们视为新对象(在DB中插入),因为EF将始终将分离实体的整个对象图放入Added状态。在您的工作示例中,您是否在DB中获得重复的CostTypes ?

  • 最后一段假设CostType的键是在DB中自动生成的,如您所说。如果没有,你会得到一个PK约束违反,而不是重复的实体。

  • 如果CostTypeCost的密钥真的是自动生成的身份,我想知道你提到的PK违反是从哪里来的。每次插入都会创建一个新的唯一主键。不可能发生违反PK的情况。您能详细显示异常消息吗?

  • 你检查了所有的Cost实体你想保存真的有一个非空的CostType属性(在用户已经修复了所有验证错误)?我在你的代码中看不到任何其他可能的原因,为什么你会得到你的"Relationship-could-not-be-changed-exception",除了Cost对象中至少有一个CostTypenull