C# 如何在代码隐藏中设置导航属性的值?

C# 如何在代码隐藏中设置导航属性的值?,c#,entity-framework,navigation-properties,C#,Entity Framework,Navigation Properties,我有一个名为Cost的实体,它的必需属性为CostType Cost类有一个GetNew()方法,用于设置所有成本的默认值: public static GetNew() { Cost cost = new Cost (); foo.CostType = Lists.CostTypes.FirstOrDefault(); // Other Default Values return foo; } 列表.CostTypes是一个静态列表,在启动时从EF中提取并在

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

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

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

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

首先在
GetNew()
方法中设置CostType之后,我在代码中设置CostType时遇到问题

例如,以下代码读取excel文件,并根据excel文件中的列设置默认类型,如果找不到匹配项,则设置为null

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文件时删除手动设置成本的代码行,则保存工作正常
  • 如果我将代码行更改为读取Lists.Costs[2],则可以节省罚款
  • 如果我删除
    GetNew()
    中设置默认值的代码行,我会收到一个错误,告诉我我违反了CostTypes的PK规则,这意味着它试图插入成本类型
  • 将显示类型的组合框更改为其他类型仍然会产生相同的错误
  • 从excel文件加载成本后,我的常规添加/编辑表单在更改类型并尝试保存时会抛出相同的错误。如果我不加载excel文件,它们工作正常
我仍在学习实体框架,但到目前为止,它只是一个令人沮丧和头痛的使用。有人知道我的问题是什么以及我如何解决它吗

编辑

这是斯劳玛要求的信息。我保持简单,排除不相关的对象

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

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

  • 导入的Excel文件将大多数成本映射到匹配的
    CostType.Name
    ,但是Excel文件中的字符串可能与
    CostType
    不匹配,因此
    列出.CostTypes.FirstOrDefault(t=>t.Name==行[0].ToString()可以为
    Cost.Type
    属性指定一个
    NULL
    值。但这似乎不是问题,因为表单仍然会显示成本列表及其默认选定项目。成本类型为
    NULL
    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();
    }
}

这并不是一个令人满意的答案,而是根据问题中的信息和对问题的评论,猜测和开放性问题的混合:

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

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

  • 另一方面,当<代码> CasyType 实体没有被附加时,你应该在你的数据库中得到重复的成本类型,因为EF会把它们看作新的对象(插入到数据库中)。当您为您的
    成本
    实体调用
    AddObject
    时,因为EF将始终将分离实体的整个对象图置于
    Added
    状态。在工作示例中,数据库中是否有重复的成本类型?如果没有,那么代码片段中缺少一些重要的内容

  • 最后一段假设
    CostType
    的键是在数据库中自动生成的,如您所说。否则,您将得到PK约束冲突,而不是重复的实体

  • 如果
    CostType
    Cost
    的键真的是自动生成的身份,我想知道你提到的PK违规是从哪里来的。每次插入都会创建一个新的唯一主键。永远不会发生PK违例事件。您能详细显示异常消息吗

  • 您是否检查了所有要保存的
    成本
    实体是否确实具有非空的
    成本类型
    属性(在用户修复了所有验证错误之后)?我在您的代码中找不到任何其他可能的原因来解释为什么您会得到“关系无法更改异常”,除了至少有一个
    成本
    对象
    成本类型


    • 我想出来了。。。。这是一些不同事物的混合

      创建新的
      成本
      和sett
      
      public static class Lists
      {
          public static List<CostType> CostTypes { get; private set; }
      
          static Lists()
          {
              CostTypes = DAL<CostEntities>.GetList<CostType>("Name");
          }
      }