Lỗi - tràn SqlDateTime. Phải trong khoảng từ 1/1/1753 12:00:00 AM đến 12/31/9999 11:59:59 PM


82

Tôi đã sử dụng đoạn mã này mà tôi đã viết và nó hoạt động theo cách không rõ ràng nhất. Tôi muốn chèn một hàng vào cơ sở dữ liệu bao gồm hai cột DateTime:

myrow.ApprovalDate = DateTime.Now
myrow.ProposedDate = DateTime.Now

Tuy nhiên, khi tôi cập nhật cơ sở dữ liệu, tôi nhận được lỗi này:

SqlDateTime tràn. Phải trong khoảng từ 1/1/1753 12:00:00 AM đến 12/31/9999 11:59:59 PM.

Tôi thậm chí đã thử sao chép một giá trị được chèn từ cơ sở dữ liệu và mã hóa nó vào đối tượng đang được cập nhật:

// I copied this value from the DB
myrow.ApprovalDate =  Convert.ToDateTime("2008-12-24 00:00:00.000");

Vẫn một lỗi tương tự, điều kỳ lạ là thủ thuật trên đã hoạt động cho lần chèn đầu tiên vào DB nhưng không thành công kể từ đó. Bất kỳ ý tưởng những gì đang xảy ra?


Đăng mã của bạn. Ngoài ra, bạn có thể xem xét chỉ kiểm tra những gì linq đang xây dựng dưới vỏ bọc.
NotMe

Câu trả lời:


87

A DateTimetrong C # là một kiểu giá trị, không phải là một kiểu tham chiếu, và do đó không thể rỗng. Tuy nhiên, nó có thể là hằng số DateTime.MinValuenằm ngoài phạm vi của DATETIMEkiểu dữ liệu Máy chủ Sql .

Các kiểu giá trị được đảm bảo luôn có giá trị (mặc định) (bằng 0) mà không cần phải luôn đặt rõ ràng (trong trường hợp này là DateTime.MinValue).

Kết luận là bạn có thể có một giá trị DateTime chưa được đặt mà bạn đang cố gắng chuyển vào cơ sở dữ liệu.

DateTime.MinValue = 1/1/0001 12:00:00 AM
DateTime.MaxValue = 23:59:59.9999999, December 31, 9999, 
                    exactly one 100-nanosecond tick 
                    before 00:00:00, January 1, 10000

MSDN: DateTime.MinValue


Về máy chủ Sql

datetime
Dữ liệu ngày và giờ từ ngày 1 tháng 1 năm 1753 đến ngày 31 tháng 12 năm 9999, với độ chính xác đến một phần trăm giây (tương đương 3,33 mili giây hoặc 0,00333 giây). Giá trị được làm tròn đến gia số .000, .003 hoặc .007 giây

smalldatetime
Dữ liệu ngày và giờ từ ngày 1 tháng 1 năm 1900 đến ngày 6 tháng 6 năm 2079, với độ chính xác đến từng phút. giá trị smalldatetime với 29,998 giây hoặc thấp hơn được làm tròn xuống đến phút gần nhất; các giá trị có 29,999 giây hoặc cao hơn được làm tròn đến phút gần nhất.

MSDN: Sql Server DateTime và SmallDateTime


Cuối cùng, nếu bạn thấy mình đang chuyển C # DateTimedưới dạng chuỗi sang sql, bạn cần định dạng nó như sau để giữ lại độ chính xác tối đa và ngăn máy chủ sql gặp lỗi tương tự.

string sqlTimeAsString = myDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff");

Cập nhật (8 năm sau)

Cân nhắc sử dụng loại DateTime2dữ liệu sql phù hợp hơn với .net DateTimevới phạm vi ngày 0001-01-01 through 9999-12-31và phạm vi thời gian00:00:00 through 23:59:59.9999999

string dateTime2String = myDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffff");

MSDN datetime2 (Giao dịch-SQL)


6
Cảm ơn bạn đã chỉ ra về việc DateTimekhông được nullable trong C #!
Tomas Aschan

80

Tôi thấy việc sử dụng các cách sau hoạt động khá tốt cho ngày tối thiểu / tối đa của SQL sau nhiều lỗi liên quan đến DB:

DateTime rngMin = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;

DateTime rngMax = (DateTime)System.Data.SqlTypes.SqlDateTime.MaxValue;

2
Điều này lẽ ra đã nhận được nhiều phiếu bầu nhất và cũng là câu trả lời chính xác.
Taha Rehman Siddiqui

Tuy nhiên, hãy lưu ý rằng có một vài sự khác biệt giữa DateTime.MaxValueSqlDateTime.MaxValue.Value. SQL Server 2014 và SQL Server 2016 (không kiểm tra những người khác) chấp nhận DateTime.MaxValuecái nào - đủ buồn cười - lớn hơn SqlDateTime.MaxValue.Value.
Manfred

10

Hãy cẩn thận khi so sánh .Net DateTime với SqlDateTime.MinValue hoặc MaxValue. Ví dụ, phần sau sẽ đưa ra một ngoại lệ:

DateTime dte = new DateTime(1000, 1, 1);
if (dte >= SqlDateTime.MinValue)
    //do something

Lý do là MinValue trả về SqlDateTime, không phải DateTime. Vì vậy, .Net cố gắng chuyển đổi dte thành SqlDateTime để so sánh và vì nó nằm ngoài phạm vi SqlDateTime có thể chấp nhận được nên nó ném ngoại lệ.

Một giải pháp cho điều này là so sánh DateTime của bạn với SqlDateTime.MinValue. Giá trị .


1
Ngoài ra còn có tùy chọn để sử dụng SqlDateTime.MinValue.Valuehoặc SqlDateTime.MaxValue.Valuecả hai đều thuộc loại DateTime. Không biết khi nào chúng được giới thiệu. Tuy nhiên, hãy lưu ý rằng có một vài sự khác biệt giữa DateTime.MaxValueSqlDateTime.MaxValue.Value. SQL Server 2014 và SQL Server 2016 (không kiểm tra những người khác) chấp nhận DateTime.MaxValueđiều đó - đủ buồn cười là lớn hơn SqlDateTime.MaxValue.Value.
Manfred

9

Mã bạn có cho hai cột có vẻ ổn. Tìm kiếm bất kỳ cột ngày giờ nào khác trên lớp ánh xạ đó. Ngoài ra, hãy kích hoạt đăng nhập trên datacontext để xem truy vấn và các tham số.

dc.Log = Console.Out;

DateTime được khởi tạo thành 0 của c # - là 0001-01-01. Điều này được linqtosql truyền tới cơ sở dữ liệu thông qua chuỗi sql theo nghĩa đen: '0001-01-01'. Sql không thể phân tích cú pháp ngày giờ T-Sql kể từ ngày này.

Có một số cách để giải quyết vấn đề này:

  • Đảm bảo rằng bạn khởi tạo tất cả thời gian ngày tháng với giá trị mà SQL có thể xử lý (chẳng hạn như 0: 1900-01-01 của Sql)
  • Hãy chắc chắn rằng bất kỳ thời điểm ngày đó đôi khi có thể được bỏ qua là nullable datetimes

1
Tôi thường sử dụng 1970/01/01 mà là một kỷ nguyên chung cho thời gian máy tính (unix time_t và JavaScript)
Tracker1

Cảm ơn về mẹo chuyển hướng Nhật ký sang Console.Out.
Jan Aagaard

8

Lỗi này xảy ra nếu bạn đang cố gắng đặt biến kiểu DateTime thành null . Khai báo biến là nullable, tức là DateTime? . Điều này sẽ giải quyết vấn đề.


1
Đây là câu trả lời cho sự cố tràn của tôi, tôi đã có ngày thứ hai trên bàn mà tôi không đưa ra giá trị, và vì vậy khi tôi đặt nó là nullable thì chèn đã hoạt động. Cảm ơn!
mkimmet

3

Đôi khi để viết ít mã, nó được sử dụng để đặt các trường của máy chủ SQL như ngày, giờ và ID trên chèn bằng cách đặt giá trị mặc định cho các trường thành GETDATE()hoặc NEWID().

Trong những trường hợp như vậy, thuộc tính Giá trị được tạo tự động của các trường đó trong các lớp thực thể phải được đặt thành true.

Bằng cách này, bạn không cần phải đặt giá trị trong mã (ngăn tiêu thụ năng lượng !!!) và không bao giờ thấy ngoại lệ đó.


2

Sử dụng phương pháp mở rộng

 public static object ToSafeDbDateDBnull(this object objectstring)
    {
        try
        {
            if ((DateTime)objectstring >= SqlDateTime.MinValue)
            {
                return objectstring;
            }
            else
            {
                return DBNull.Value;
            }
        }
        catch (Exception)
        {

            return DBNull.Value;
        }

    }

DateTime objdte = new DateTime(1000, 1, 1);
dte.ToSafeDbDateDBnull();

1

Điều đó thường có nghĩa là giá trị rỗng đang được đăng lên truy vấn thay vì giá trị mong muốn của bạn, bạn có thể thử chạy SQL Profiler để xem chính xác những gì đang được chuyển đến SQL Server từ linq.


1

Thông thường loại lỗi này xuất hiện khi bạn thực hiện chuyển đổi DateTime hoặc phân tích cú pháp. Kiểm tra cài đặt lịch trong máy chủ nơi ứng dụng được lưu trữ, chủ yếu là múi giờ và định dạng ngày ngắn và đảm bảo lịch được đặt ở múi giờ phù hợp cho vị trí. Hy vọng điều này sẽ giải quyết vấn đề.


0

Tôi đang nhìn thấy điều tương tự. Lỗi không xảy ra khi chèn hàng mà xảy ra trên bản cập nhật. bảng mà tôi đang tham chiếu có hai cột DateTime, cả hai cột này đều không có giá trị rỗng.

Tôi đã nhận được kịch bản xuống để nhận hàng và ngay lập tức lưu nó (không thay đổi dữ liệu). Nhận hoạt động tốt nhưng cập nhật không thành công.

Chúng tôi đang sử dụng NHibernate 3.3.1.4000


0

Nếu bạn đang sử dụng NHibernate, hãy kiểm tra xem các thuộc tính DateTime thích hợp có thể nullable được đặt thành nullable trong ánh xạ hay không.


0

Nếu bạn đặt Datetime là nullable như DateTime? trong mô hình của bạn, nó không có ngoại lệ. tôi đã giải quyết vấn đề như thế này trong trường hợp của tôi


0

Trong trường hợp của tôi, lỗi này đã xuất hiện vì Cột ngày của bảng không thể rỗng

Như sau:

Create Table #TempTable(
 ...
 ApprovalDate datatime not null.
 ...)

Để tránh lỗi này, chỉ cần làm cho nó không có khả năng

 Create Table #TempTable(
 ...
 ApprovalDate datatime null.
 ...)

-3

DateTime.MinValue và DateTime.MaxValue

DateTime.MinValue = 1/1/0001 12:00:00 AM

DateTime.MaxValue = 23:59:59.9999999, December 31, 9999, 

                exactly one 100-nanosecond tick 

                before 00:00:00, January 1, 10000 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.