如何确保 Linq to Sql 不会覆盖或违反不可为空的 DB 默认值?

Posted

技术标签:

【中文标题】如何确保 Linq to Sql 不会覆盖或违反不可为空的 DB 默认值?【英文标题】:How do I ensure Linq to Sql doesn't override or violate non-nullable DB default values? 【发布时间】:2008-10-14 15:44:37 【问题描述】:

我有一个带有这些字段的表的 SQL Server 数据库:

    bit,默认值为 1,NOT NULL。 一个smalldatetime,默认值为gettime()NOT NULL。 一个没有默认值的intIDENTITYNOT NULL

当我为此表生成 Linq to SQL 时,会发生以下情况:

    bit 没有得到特殊处理。 smalldatetime 没有得到特殊处理。 int 被标记为IsDbGenerated

这意味着当我使用 Linq to SQL 进行插入时,会发生以下情况:

    bit 将作为 0 发送,覆盖默认值。 对吗? smalldatetime 将作为未初始化的System.DateTime 发送,在 SQL Server 中产生错误,因为它不属于 SQL Server smalldatetime 范围。 对吗? IsDbGenerated int 将不会被发送; DB 将生成一个值,然后 Linq to SQL 将读回该值。

我必须进行哪些更改才能使此方案生效?

总结一下:我想要具有 DB 分配的默认值的不可空字段,但我不想要它们 IsDbGenerated,如果这意味着在使用 Linq to SQL 进行更新或插入时我无法为它们提供值。我也不想要他们IsDbGenerated,如果这意味着我必须将 Linq 生成的代码手动修改为 SQL。

编辑:答案似乎是这是当前 Linq to SQL 的一个限制。

【问题讨论】:

重复:***.com/q/1120858/11683(不投票结束,两者同样有用)。 【参考方案1】:

Linq-To-Sql 生成的类不使用默认值约束。

也许在未来,但问题是约束并不总是简单的值,它们也可以是像GetDate() 这样的标量函数,所以 linq 必须知道如何翻译这些值。简而言之,它甚至没有尝试。它也是一种非常特定于数据库的类型。

您可以编写代码生成器来创建实体部分类,您可以在其中提取默认值常量。 或者,您的业务层代码可以在 xml 文件的构造函数中设置默认值,您需要做的就是使 xml 文件保持最新。 您可以模拟 sql 并通过在向数据库提交更改之前检查 ChangeSet 来添加默认值,而不是在构造函数中进行工作。

CodeProject - Setting Default Values for LINQ Bound Data 详细描述了您遇到的问题

【讨论】:

"linq 必须知道如何翻译这些" - 为什么?它可以只允许在创建/更新时不传递任何内容,然后再将它们读回。这就是 IsDbGenerated 字段的工作方式,除了它们在 Linq 端的只读状态。 当然,它可以允许它,但它不允许。 IsDbGenerated 仅适用于此时的关键列。 “linq 会以某种方式......”只是我对为什么会出现这种情况的看法。 似乎 IsDbGenerated 现在也可用于非键列。【参考方案2】:

我遇到了同样的问题,bzlm,并得出了同样的结论。使用 Linq To Sql 获取具有 DB 分配的默认值的不可空字段根本没有好方法。

我所采用的解决方法是添加一个 SetDefaults() 方法,该方法与 CodeProject 上的 Robert Paulson 链接的方法非常相似,并在我的表实体基类的默认构造函数中调用它。它对我很有效,因为 95% 的时间,我设置的是 0、空字符串或 getdate()。

【讨论】:

【参考方案3】:

这意味着当我使用 Linq to SQL 进行插入时,以下将 发生:

    该位将作为 0 发送,覆盖默认值。正确的? - 正确 smalldatetime 将作为未初始化的 System.DateTime 发送, 在 SQL Server 中产生错误,因为 它不属于 SQL Server 小日期时间范围。正确的? - 发送的是 DateTime.MinValue 不会发送 IsDbGenerated int;数据库将生成一个值 然后Linq to SQL 会读回。 - 如果设置了 DB generated,则该值由数据库创建,如果没有,则 Linq 期望用户设置该值。

如果您不使用自动属性,最好将它们设置在对象的构造函数中或私有字段中。

【讨论】:

听起来你在说 SQL Server 值中字段的默认值不可能与 Linq To SQL 结合使用。这是正确的吗? 有可能,但事后您无法更改它们。如果您希望能够更改它们,那么您应该在构造函数中创建它们。 对不起,我不明白。什么是可能的?在什么事实之后不能改变什么?是否可以让 Linq To SQL 执行插入并在使用的数据库中指定“默认值”? 不要使用构造函数,有一个特殊的分部方法叫做 OnCreate 。看到这个问题:***.com/questions/82409/… 其实是OnCreated。 Longhorn213 的回答非常混乱,而且他/她似乎也无缘无故地编辑了我原来的问题。忽略他/她。【参考方案4】:

您可以为您的数据上下文(部分类)创建另一个文件,然后使用 InsertYOURENTITY 和 UpdateYOURENTITY 部分方法来检查您的属性并分配正确的值。 在您的代码之后调用 ExecuteDynamicInsert 或 ExecuteDynamicUpdate 并设置好。

【讨论】:

实际上,在 BLL 中执行此操作的推荐方法是为实体实现部分方法 OnCreated(),而不是您建议的方法。不过,这与我的问题无关。我的问题是关于 SQL Server 中的默认值,而不是 BLL 中的默认值。

以上是关于如何确保 Linq to Sql 不会覆盖或违反不可为空的 DB 默认值?的主要内容,如果未能解决你的问题,请参考以下文章

WP7 Linq To SQL(SQL CE) IDataErrorInfo

LINQ to SQL和外键的基本误解

使用DISTINCT时,LINQ to SQL不生成ORDER BY?

LINQ to SQL 或任何其他启用了 LINQ 的 ORM 是不是支持许多关联过滤?

linq to sql、Entity Framework 和 NHibernate 的性能如何?

linq to sql 怎么查前5条记录