如何在后面的代码中设置导航属性的值?
本文关键字:属性 导航 设置 在后面 代码 | 更新日期: 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有问题。
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
NULLvalue 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
NULLCostType 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
中,即使我从未调用AddObject
或AttachObject
。一旦我意识到,我开始调用DeleteObject
的成本是不会被保存的,它清除了我得到的第一个错误。
我得到的第二个错误(重复的PK)是因为我在循环我的新成本并调用AddObject
和SaveChanges
。由于将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约束违反,而不是重复的实体。 -
如果
CostType
和Cost
的密钥真的是自动生成的身份,我想知道你提到的PK违反是从哪里来的。每次插入都会创建一个新的唯一主键。不可能发生违反PK的情况。您能详细显示异常消息吗? -
你检查了所有的
Cost
实体你想保存真的有一个非空的CostType
属性(在用户已经修复了所有验证错误)?我在你的代码中看不到任何其他可能的原因,为什么你会得到你的"Relationship-could-not-be-changed-exception",除了Cost
对象中至少有一个CostType
是null
。