为什么没有更新与WillCascadeOnDelete等价的功能?
为什么没有更新与WillCascadeOnDelete等价的功能?
在EF(Entity Framework)的Code-First中建立一对多关系时,可以选择是否应该级联删除,示例如下:\n
modelBuilder.Entity() .HasRequired(asmt => asmt.CreatedByUser) .WithMany(usr => usr.Assessments) .HasForeignKey(asmt => asmt.CreatedByUserId) .WillCascadeOnDelete(true);
\n这将转换为SQL中外键定义的ON DELETE CASCADE
部分,即:\n
ALTER TABLE [dbo].[Assessment] WITH CHECK ADD CONSTRAINT [FK_dbo.Assessment_dbo.User_CreatedById] FOREIGN KEY([CreatedById]) REFERENCES [dbo].[User] ([UserId]) ON DELETE CASCADE GO
\n然而,在Fluent API中似乎没有类似的方法可以控制ON UPDATE CASCADE
的值,例如.WillCascadeOnUpdate()
。为什么没有呢?
为什么没有更新等效的WillCascadeOnDelete?
在使用ORM时,不能更改主键是一个常见问题。
尤其是当主键是非自增字段(比如GUID)时,更改主键是一个错误的做法。
主键应该是不可变的,如果主键发生改变,那么你选择了错误的字段。
有时候可能需要改变主键,但这并不意味着你应该使用它。
主键不应该有业务含义,只是因为一些数据库支持ON UPDATE CASCADE概念,并不意味着它是一个好主意。
ORM不支持这种操作,因为POID被定义为不可变的。
那么在哪里定义了POID是不可变的?
在所有主流ORM的设计和实现中。
所以,你是说如果你想要一个使用GUID作为主键的系统,而且(由于遗留原因或者需要与其他数据源同步)有时候需要更新这些GUID,那么你应该避免使用ORM?
是的,这是正确的。有一些方法可以绕过这个问题(使用原始SQL更新ID,并希望没有其他地方引用旧实体),但是我不知道任何一个ORM允许在支持的工作流中修改主键。
为什么没有与WillCascadeOnDelete相等的更新方法?
Entity Framework通过导航属性处理关系,所以所有这些关系都已经启用了ON UPDATE CASCADE。另一方面,我不确定你能否直接从Entity Framework更改实体的主键。
在Entity Framework中,我们可以使用导航属性来处理实体之间的关系。这意味着当我们删除一个实体时,相关的关系也会被删除(通过WillCascadeOnDelete)。然而,当我们尝试更新一个实体的主键时,却没有类似的更新方法。
这个问题的出现是因为Entity Framework并没有提供一个与WillCascadeOnDelete相等的更新方法。这可能是因为更新一个实体的主键可能会导致与其他实体之间的关系失效。
然而,我们可以通过其他方法来解决这个问题。一个解决方法是先删除与该实体相关的关系,然后再更新实体的主键。这样,我们就可以确保更新后的主键与其他实体之间的关系保持有效。
下面是一个示例代码,演示了如何通过先删除相关关系再更新主键来解决这个问题:
using System; using System.Linq; public class MyEntity { public int Id { get; set; } public string Name { get; set; } } public class MyContext : DbContext { public DbSetMyEntities { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity () .HasMany(e => e.RelatedEntities) .WithRequired(e => e.MyEntity) .WillCascadeOnDelete(true); } } public class Program { static void Main(string[] args) { using (var context = new MyContext()) { var entity = context.MyEntities.FirstOrDefault(); // 删除与该实体相关的关系 foreach (var relatedEntity in entity.RelatedEntities.ToList()) { context.RelatedEntities.Remove(relatedEntity); } // 更新实体的主键 entity.Id = 2; context.SaveChanges(); } } }
通过以上代码,我们可以先删除与实体相关的关系,然后再更新实体的主键。这样,我们就可以在不失去关系的情况下更新实体的主键。