更新 : 2020-01-05

今天记入一下 alternate key 遇到的主次疑惑

alternate 会产生多个 foreignkey 的情况

比如我想选一个 state 那么前提是我要先选 country, 这样就需要有 2 个 foreignkey

所谓的主次疑惑是说在上面这个情况下我是要一个 state 所以当这个 state 换 country 后, 我也是要跟着它走的. 整个都是 cascade update.

另一种情况可能是我先选了一个 country, 然后我想再选一个 state, 这种情况下, country 是确定的. state 是依赖 country 的,

这时候如果 state 突然换了 country, 那么我其实是不想跟着换的,反而要阻止它,因为逻辑错了。

更新: 2019-12-23

在 ef 如果要拿不是 Id 来做 foreignkey 那么它就肯定是 alternative key 了,

当我们调用 HasPrincipalKey 这个时候 alternative key 就自动被做出来了。

在 sql 的话,其实并没有这么一个条件.

更新: 2019-11-01

虽然 Natural Key 很自然,但是维护起来成本很挺高

ef core 给了我们 Alternate Keys + composition

但是目前依然没有解决修改的问题

https://github.com/aspnet/EntityFrameworkCore/issues/4073

里面提到了使用 update cascade 的做法,虽然很不错,但是 sql server 的 cascade 不可以 multiple path

https://stackoverflow.com/questions/851625/foreign-key-constraint-may-cause-cycles-or-multiple-cascade-paths

https://support.microsoft.com/en-us/help/321843/error-message-1785-occurs-when-you-create-a-foreign-key-constraint-tha

sql server 官方给出的意见是使用 trigger instand of

这个方法和 cascade 有很大区别的,正常情况下 cascade 的逻辑是交给子表,这种情况下扩展一个新的表是无需修改之前任何代码的。

但是如果使用了 trigger 就不得不把所有的逻辑放到一起了.

我们只能使用 trigger instand of  不可以使用 trigger after 因为 foreignkey 约束会直接报错而导致 delete 没有被执行,而 trigger 自然也不会触发了

所以只能使用 instand of, instand of 不是 before ,它的意思是替代,也就是说你得自己写过 delete 逻辑.

delete 尚可接受,但是 alternative key 需要 cascade update, 这个 update 语句可就不好写了..

https://dba.stackexchange.com/questions/77273/instead-of-trigger-continue-with-operation-after-custom-logic

目前我的做法是当遇到 cascade cycle 时, 把逻辑写在 application 而不交给 sql server trigger.

cascade update 手动维护需要暂时解开约束

https://stackoverflow.com/questions/159038/how-can-foreign-key-constraints-be-temporarily-disabled-using-t-sql

类似

alter table People nocheck constraint FK_People_Countries;
update People set country = 'Singapore2' where country = 'Singapore';
update Countries set name = 'Singapore2' where name = 'Singapore';
alter table People with check check constraint FK_People_Countries;

更新: 2019-10-27 

https://docs.microsoft.com/en-us/ef/core/modeling/relationships

https://docs.microsoft.com/en-us/ef/core/modeling/alternate-keys

composition alternate keys

有些时候 key 需要 2 个 column 才可以.比如很常见的 country, state

country 和 state 是 1-n 的关系

address 里需要记入 country and state

如果关系只是 country 1-n address 和 state 1-n address 的话

我们就无法确保, state 是 under country 的

这个时候就可以用 composition alternate keys 了

modelBuilder.Entity<Country>().HasAlternateKey(p => p.name);
modelBuilder.Entity<Country>().HasMany(p => p.states).WithOne(p => p.country).HasForeignKey(p => p.countryKey).HasPrincipalKey(p => p.name).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Country>().Property(p => p.name).IsRequired(true).HasMaxLength();
modelBuilder.Entity<Country>().HasMany(p => p.people).WithOne(p => p.country)
.HasForeignKey(p => p.countryKey)
.HasPrincipalKey(p => new { p.name }).OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity<State>().HasAlternateKey(p => new { p.countryKey, p.name });
modelBuilder.Entity<State>().Property(p => p.name).IsRequired(true).HasMaxLength();
modelBuilder.Entity<State>().HasMany(p => p.people).WithOne(p => p.state)
.HasForeignKey(p => new { p.countryKey, p.stateKey })
.HasPrincipalKey(p => new { p.countryKey, p.name });

Surrogate Key vs Natural Key, 争论多年

https://www.mssqltips.com/sqlservertip/5431/surrogate-key-vs-natural-key-differences-and-when-to-use-in-sql-server/

2 个都有好处坏处.

ef core 对 Natural Key 支持比较弱.

使用 Alternate Keys 来实现

https://docs.microsoft.com/en-us/ef/core/modeling/alternate-keys

它最糟糕的地方是,目前不支持修改

https://stackoverflow.com/questions/36200436/cannot-update-alternate-key-entity-framework-core-1-0

https://github.com/aspnet/EntityFrameworkCore/issues/4073

对我来说大部分情况下 Surrogate Key 是好用的

但它凡事都要 join 表比较麻烦, filter 也好,查询值也好,都一定要 join.

所以我认为 Natural Key 只在一种情况下特别好

join 的 table 只是一个 primary column

比如有个 category 和 product

category 只有一个 name, 如果做一个 category 表那每次 product 就得 join category 为了拿唯一的 category name。

而如果 product 直接记入 category name 就方便多了.

短期内 ef 应该是不会支持 update 这个功能的,saveChanges 就报错说不能 edit 了,

目前的 workaround 是去 override migration 生成出来的 file 添加 onUpdate cascade,

table.ForeignKey(
name: "FK_Products_Categories_categoryName",
column: x => x.categoryName,
principalTable: "Categories",
principalColumn: "name",
onDelete: ReferentialAction.Restrict,
onUpdate: ReferentialAction.Cascade);

然后更新的时候直接调用语句.

var commandText = "update Categories set name = @categoryName where Id = @Id";
var categoryName = new SqlParameter("@categoryName", "man");
var Id = new SqlParameter("@Id", );
var ok = Db.Database.ExecuteSqlCommand(commandText, new[] { categoryName, Id });

最新文章

  1. Drupal7网站+IIS7.0+PHP+MySql
  2. 【BZOJ】2178: 圆的面积并
  3. 使用substring和split方法从字符串中抽取一组清单
  4. ETL,ESB,BPM为什么要这些图形
  5. poj - 2431 Expedition (优先队列)
  6. Window.Open参数、返回值
  7. spring中基础核心接口总结
  8. HDOJ 1429 胜利大逃亡(续) (bfs+状态压缩)
  9. JVM调优总结(十二)-参考资料
  10. Cocos2dx 3.0 过渡篇(二十五)死不了的贪食蛇(触摸版)
  11. TCP/IP协议头部结构体(网摘小结)(转)
  12. 【Java学习笔记之八】java二维数组及其多维数组的内存应用拓展延伸
  13. 第三方页面嵌入到web项目的方案 之 使用iframe嵌入
  14. html中节点类型
  15. Random Forest总结
  16. ionic2中使用datetime组件如何默认设置当前时间?
  17. Http协议请求头、响应头、响应码
  18. [CF920G]List Of Integers
  19. nginx关闭目录浏览功能
  20. [No000016C]做企业分析的三个重要工具

热门文章

  1. js for (i=0;i&lt;a.length;a[i++]=0) 中等于0怎么理解?
  2. onNewIntent
  3. 5.性能测试工具比较:Jmeter和LR
  4. Google Directions API 中路线编码解析
  5. NIO单一长连接——dubbo通信模型实现
  6. Qt编写数据可视化大屏界面电子看板12-数据库采集
  7. kubernetes监控(12)
  8. java调用js脚本
  9. ORA-03114: not connected to ORACLE
  10. Node.js使用Express.Router