建议请:使用实体框架时SQL Server身份与唯一标识符密钥

时间:2009-03-02 22:20:26

标签: sql-server entity-framework replication identity uniqueidentifier

我正在设计一个相当复杂的系统。我们主要关注的一个问题是支持SQL Server对等复制。这个想法是支持几个地理上分离的节点。

第二个问题是在中间层使用现代ORM。我们的第一选择一直是实体框架,主要是因为开发人员喜欢使用它。 (他们喜欢LiNQ的支持。)

所以这就是问题所在:

考虑到点对点复制,我决定使用uniqueidentifier,默认值为newsequentialid(),用于每个表的主键。这似乎在避免关键冲突和减少索引碎片之间提供了良好的平衡。

然而,事实证明当前版本的Entity Framework有very strange limitation:如果实体的键列是唯一标识符(GUID),那么它不能配置为使用提供的默认值(newsequentialid())由数据库。应用程序层必须生成GUID并填充键值。

所以这是辩论:

  1. 放弃实体框架并使用其他ORM:
    • 使用NHibernate并放弃LiNQ支持
    • 使用linq2sql并放弃将来的支持(更不用说绑定到DB上的SQL Server)
  2. 放弃GUID并采用另一种PK策略
  3. 设计一种在应用层生成顺序GUID(COMB?)的方法
  4. 我倾向于选择1使用linq2sql(我的开发人员非常喜欢linq2 [stuff])和3.这主要是因为我对支持我们所针对的复制方案的备用关键策略有点无知,同时还要保留从开发人员的角度来看,这些都是明智的。

    非常感谢任何见解或意见。

6 个答案:

答案 0 :(得分:8)

我是克雷格的第二个建议 - 选项4.

您始终可以使用由中间层填充的GUID列作为PRIMARY KEY(这是一个LOGICAL构造)。

为了避免大量索引(因此:表)碎片,使用一些其他键(理想情况下是一个INT IDENTITY列)作为CLUSTERING KEY - 这是一个物理数据库构造,可以与主键分开。

默认情况下,主键是群集键 - 但不一定是这样。实际上,我通过在“继承”的数据库上做了这样的改进来提高性能并大幅降低碎片 - 添加一个INT IDENTITY列并将聚类键放在那个小的,不断增加的,永不改变的INT上 - 就像一个魅力!

马克

答案 1 :(得分:5)

咦?我认为你的三个选择都是错误的选择。考虑选项4:

  

4)将实体框架与非顺序,客户​​端生成的GUID一起使用。

对于框架本身插入的新行,EF无法看到DB服务器生成的GUID ,但是您不需要在数据库服务器上生成GUID。您可以在创建实体实例时在客户端上生成它们。 GUID的重点在于您生成它的位置无关紧要。至于复制数据库生成的GUID,EF会很好地看到它们。

您的客户端GUID不会是顺序的(使用Guid.NewGuid()),但它们将在全球范围内保证唯一。

我们在运输,生产软件中进行复制。它 工作。

答案 2 :(得分:4)

另一个选项(发布时不可用)是升级到EF 4,它支持服务器生成的GUID。

答案 3 :(得分:0)

为什么不使用标识列?如果您正在进行合并复制,您可以让每个系统从单独的种子开始并在一个方向上工作(例如,节点a从1开始并添加1,节点b从0开始并减去一个)...

答案 4 :(得分:0)

如果您真的坚持使用NewSequentialID(),则可以使用存储过程。您可以将过程中的结果列绑定到相应的属性,插入后,SQL生成的GUID将反馈到对象中。

不幸的是,您必须为所有三个操作(插入,更新,删除)定义SP,即使其他操作使用默认值正确完成也是如此。您还需要维护SP代码并确保在进行更改时与EF模型同步,这可能会因为额外的开销而使此选项不具吸引力。

http://blogs.msdn.com/bags/archive/2009/03/12/entity-framework-modeling-action-stored-procedures.aspx有一个分步示例,非常简单。

答案 5 :(得分:0)

使用newseqid和你自己的orm(并不难)使用linq