Pau*_*mke 50 .net vb.net sql-server entity-framework
我正在尝试从实体框架中更新复合主键的一个值,并且我收到此错误:"属性'CustomerID'是对象的关键信息的一部分,无法修改."
这是我的代码:
Dim customer As Customer = (From c In db.Customer Where c.CustomerID = "xxx" AndAlso c.SiteKey = siteKey).FirstOrDefault
customer.CustomerID = "fasdfasdf"
db.SaveChanges()
Run Code Online (Sandbox Code Playgroud)
这似乎太简单了.是否真的无法在实体框架内更新主键?我找不到有关该主题的任何文档.谢谢!
小智 59
我有博士学位 在cs中 - 在数据库领域,所以这个答案将与程序员的观点略有不同.对于所有关于奥利弗Hanappi,一键便可偶尔不改变,如果它不是一个代理键.例如自然键或复合键.例如.可以在美国更改您的SSN.但是,许多程序员多年来都会认为这是一个不可更改的密钥,并将其用作原样.更改由外键组成的复合主键更为常见.
我正在处理一个有三元关系的数据库.特别是三个实体(外键是各自表中的代理主键).但是,要在更改第三个实体时保留两个实体之间的关系,需要更改交集表的一部分(在MSDN上也称为纯连接表)主键.这是一个有效的设计,只能通过删除三元关系交集表并将其替换为两个二进制关系表(可能有自己的代理键)来改进.EF会处理这个问题.此设计更改将使(多个 - >多个) - >多个或Parent1-Parent2 - >子孙模型(如果不清楚,请阅读下面的示例).实体框架可以正常工作,因为每个关系实际上是一对多的关系.但从DB的角度来看,这是一个疯狂的设计.让我举个例子说明原因.
考虑课程,课堂和讲师在课堂上彼此相关联.类可以包括:CourseID,ClassroomID,InstructorID作为外键,并包含一个包含所有三个的复合主键.虽然是一个清晰,简洁的三元模型(三向关系),但我们可以将其分解为二元关系.这将给出两个交集表.添加代理键将满足EF,如下所示:
类(SurrogateKeyClass,InstructorID,CourseID)
ClassRoomUsed(SurrogateKeyClassroomUsed,SurrogateKeyClass,ClassRoomID)
这种设计的问题在于,我们可以将相同的课程和教师多次关联,这是之前的模型所避免的.为了避免这个问题,你可以在数据库中添加一个约束,以获得两个ID字段的唯一性,但是当你只处理代理键时,你为什么要这样做呢?但是,这个解决方案可以尽我所能地工作.然而,这不是逻辑数据库设计,因为DB中需要非自然的唯一约束.
但是,如果您不想更改数据库或无法更改数据库,则这是第二种解决方案:交叉/关联表就是这样,将两个实体或更多实体链接在一起的链接.如果更改,请删除关联并重新创建具有相应外键(导航属性)的新关联.这意味着您不会被允许在任何关系中要求子实体,但这是非常常见的.
我建议实体框架(将来)允许我们这些能够设计优雅数据库模型的人在我们想要的时候更改交集/关联表中的部分键!
免费的另一个例子:
考虑学生,课程,年级协会.学生通过成绩与课程相关联.通常这是Student和一个Course之间的多对多关联,在关联表中有一个名为grade的附加字段(关联表有有效载荷数据,如等级,交集表没有有效载荷,在MSDN中称为纯连接表,在一个地方租赁):
学生(StudentID,....)
课程(CourseID,...)
考试(StudentID,CourseID,年级)
如果有人从下拉列表中输入数据并将学生放入错误的班级,您希望他们稍后通过再次选择下拉列表并选择其他课程来更改它.在后台,您需要从Taking表中删除EF对象并重新创建它,而不会丢失等级(如果有).简单地更改外键课程ID似乎是一个更好的选择.如果这个似乎是做作的话,想出你自己的协会,但作为教授,这对我来说很自然.
结论:当你有一串关系时,最好不要允许级联和/或改变FK,但是存在需要它的合理/逻辑场景,即使不推荐作为一般的最佳实践.
此问题可能会出现以下异常,具体取决于您是分别更改模型中的导航属性还是键属性:
发生了引用完整性约束冲突:当依赖对象为Unchanged时,除非将其设置为关联的主体对象,否则无法更改作为参照完整性约束一部分的主键属性.必须跟踪主要对象,并且不标记为删除.
属性"X"是对象的关键信息的一部分,无法修改.
Shi*_*iji 21
您无法通过实体框架更新主键,因为实体框架不知道要更新哪个数据库行.
但是,如果您确实需要这样做,则可以编写更新主键的存储过程,然后从实体框架执行存储过程.
Nat*_*n W 11
你不能并且有充分的理由.查看KM评论.
我说你可以做的一件事是有两个表,一个是匿名数据,一个是在登录后存储真实用户数据.
或者你的(我没有经过测试或曾经做过)可以使用这种表布局:
---Customers----
AutoNumber PK <- This links to all other tables in your database, and does NOT change.
CustomerID <- This can change.
CustomerType <- Anonymous or logged in.
Run Code Online (Sandbox Code Playgroud)
当他们登录时,您将CustomerType和CustomerID更改为您需要的内容.
所以你的查询看起来像这样:
Dim customer As Customer = (From c In db.Customer _
Where c.CustomerID = {Some temp ID} _
AndAlso c. CustomerType = "Anonymous").FirstOrDefault
// After user logs in.
customer.CustomerID = {Make a new user ID here}
customer.CustomerType = "LoggedIn" {or what ever}
db.SaveChanges()
Run Code Online (Sandbox Code Playgroud)
请注意,自动编号主键永远不会更改.这样,您与Customers表的关系中的任何表仍然有效,并且不必对主键进行级联更新(这就像用铅笔刺伤自己的眼睛一样).
| 归档时间: |
|
| 查看次数: |
53324 次 |
| 最近记录: |