不将日期属性设置为对象会导致错误。

4
我有一个表,其中有一个非空的smalldatetime字段,默认值为getdate()。在创建表中的新记录时,我不通过LINQ To SQL语法在代码中设置smalldatetime字段, 而是让数据库设置默认值即当前日期。如果我不在代码中显式设置它,就会抛出以下错误:

SqlDateTime溢出,必须介于1753年1月1日12:00:00 AM和9999年12月31日11:59:59 PM之间。

如果我已经在数据库中设置了默认值,为什么还要在代码中设置它呢?当涉及到LINQ To SQL时,我注意到日期会出现一些奇怪的问题。

类似问题:https://dev59.com/bHVC5IYBdhLWcg3wtzut - bdukes
4个回答

3
与其将字段设置为 IsDbGenerated,您可能希望考虑将其 AutoSync 值设置为 OnInsertIsDbGenerated 不允许您在任何时候设置字段的值(这可能是您想要的“创建日期”字段,但不适用于“上次修改”字段)。
然而,如果您正在使用 ORM,请考虑一下是否希望应用程序逻辑同时存在于数据库和应用程序代码中。是否更合理通过代码(例如通过像 partial methods 中的 Insert[Entity])实现默认值?

感谢您提供关于ISDbGenerated属性的提示。 - Xaisoft

1

您需要设置生成的属性,以便 LINQ to SQL 不会在创建时发送其默认值。

该属性在实体上称为“自动生成的值”。

alt text


好的,我会尝试并让您知道。出于好奇,LINQ to SQL发送的默认值是什么? - Xaisoft
它使用.NET认为的DateTime默认值。实际上,我相信它发送的是“公元元年1月1日”。 - John Gietzen
好吧,你会认为他们至少会友善地发送当前日期,哈哈。 - Xaisoft

0
为了解决这个问题,请确保你的 LINQ To SQL 模型知道你的 smalldatetime 字段是由数据库自动生成的。
在你的 LINQ To SQL 图表中选择表字段,并找到 Properties 窗口。将 Auto Generated Value 属性调整为 True。这将确保该字段不包括在 LINQ To SQL 生成的 INSERT 语句中。

alt text

或者,您需要自己指定:

if (newCustomer.DateTimeCreated == null) {
       newCustomer.DateTimeCreated = DateTime.Now; // or UtcNow 
 }

0

LINQ To SQL在观察数据库默认值方面存在问题,无法随后更新该值。为了允许这样做,您需要在代码中设置默认值。

当创建新的对象时,如果该对象是NOT NULL且具有数据库默认值,则C#将使用默认值,例如数字和日期的MinValue,空GUID(零),等等。您可以查找这些条件并替换为自己的默认值。

这是LINQ To SQL已知的设计问题。有关详细讨论,请参见此链接:

http://www.codeproject.com/KB/linq/SettingDefaultValues.aspx

以下是一些在应用程序中设置默认值的示例代码:

private void SetDefaults(object LinqObj)
{
    // get the properties of the LINQ Object
    PropertyInfo[] props = LinqObj.GetType().GetProperties();

    // iterate through each property of the class
    foreach (PropertyInfo prop in props)
    {
        // attempt to discover any metadata relating to underlying data columns
        try
        {
            // get any column attributes created by the Linq designer
            object[] customAttributes = prop.GetCustomAttributes
            (typeof(System.Data.Linq.Mapping.ColumnAttribute), false);

            // if the property has an attribute letting us know that 
            // the underlying column data cannot be null
            if (((System.Data.Linq.Mapping.ColumnAttribute)
            (customAttributes[0])).DbType.ToLower().IndexOf("not null") != -1)
            {
                // if the current property is null or Linq has set a date time 
            // to its default '01/01/0001 00:00:00'
                if (prop.GetValue(LinqObj, null) == null || prop.GetValue(LinqObj, 
                null).ToString() == (new DateTime(1, 1, 1, 0, 0, 0)).ToString())
                {

                    // set the default values here : could re-query the database, 
                    // but would be expensive so just use defaults coded here
                    switch (prop.PropertyType.ToString())
                    {
                        // System.String / NVarchar
                        case "System.String":
                            prop.SetValue(LinqObj, String.Empty, null);
                            break;
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Int16":
                            prop.SetValue(LinqObj, 0, null);
                            break;
                        case "System.DateTime":
                            prop.SetValue(LinqObj, DateTime.Now, null);
                            break;
                    }
                }
            }
        }
        catch
        {
            // could do something here ...
        }
    }

它是否会观察到它,你只需要告诉它去观察它吗? - Xaisoft
John的回答部分正确。正如bdukes所指出的那样,您可以在永远不会更新该字段的情况下执行该操作。 - D'Arcy Rittich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接