24

DataTables được nhập mạnh hỗ trợ các kiểu trường "không thể thực hiện", ngoại trừ việc nhà thiết kế sẽ không cho phép bạn thay đổi cài đặt thành "cho phép null" cho bất kỳ trường loại giá trị nào. (ví dụ: các loại String cho phép nullable, nhưng int's không).Các loại dễ vỡ trong dữ liệu/tập dữ liệu được nhập mạnh mẽ - giải pháp?

Cách giải quyết là gọi IsMyFieldNull() bất kỳ lúc nào bạn muốn nhận Myfield. Nếu bạn truy cập MyField khi nó có chứa một null, nó sẽ gây ra một sự lừa dối.

Đây là một cơn đau đầu lớn, ngoài việc gây ra nhiều lỗi thời gian chạy khi hiển thị null có thể khiến ứng dụng của bạn gặp sự cố. Tôi đã phàn nàn với microsoft trong nhiều năm về điều này, nhưng mỗi bản phát hành mới của studio trực quan vẫn không cho phép sử dụng các loại giá trị nullable.

Câu hỏi của tôi: Bất kỳ ai biết về một phương pháp mở rộng ưa thích có thể được sử dụng để khắc phục thiếu sót lớn này?

+0

Bạn có thể sửa đổi định nghĩa thuộc tính hàng trong tệp .Designer của DataSet cho bảng, nhưng có vẻ như nó được tạo lại mỗi khi DataSet được sửa đổi thông qua trình thiết kế VS, ngay cả khi bạn không chạm vào bảng cụ thể. –

Trả lời

2

Trong VS 2008, bạn chỉ có thể nhập '0' trong thuộc tính nullvalue.
Nếu bạn đang sử dụng vs2005, bạn phải làm điều đó với một trình soạn thảo XML. Bạn phải thêm msprop:nullValue="0" làm thuộc tính vào cột.

+4

Vấn đề là, một "0" là một giá trị hợp pháp .. những gì tôi thực sự cần (hoặc muốn) là null value = null, và kiểu dữ liệu là int? thay vì int. –

1

Tôi đồng ý rằng nó sẽ là một tính năng tốt đẹp để cho phép các loại không có giá trị.

Nếu bạn đặt thuộc tính "NullValue" trên cột thành "-1" thay vì "(Ném ngoại lệ)", thuộc tính sẽ trả về -1 khi cột rỗng thay vì ném ngoại lệ. Bạn vẫn phải thiết lập cột để cho phép null.

Hoặc, bạn luôn có thể đặt kiểu dữ liệu thành "System.Object" và cho phép null = true. Bạn có thể truy cập giá trị của cột mà không phải sử dụng phương thức "IsMyFieldNull()". Giá trị của cột sẽ là "System.DbNull.Value" khi cột là null. Nếu bạn không thích sử dụng "System.DbNull.Value", bạn có thể đặt thuộc tính "NullValue" thành "(Nothing)" thay vì "(Throw exception)" và sau đó so sánh đối tượng với tham chiếu null.

+0

-1 là một giá trị hợp lệ trong db, vì vậy không thể sử dụng nó. Nhưng giữ im tâm im cũng nói về tất cả các loại giá trị. DateTime, đôi, vv –

+0

Bạn cũng có thể, theo tiêu chuẩn, sử dụng giá trị tối đa của loại giá trị để biểu thị null. Đối với một byte nó là 255 và cho một int32 nó là 2.147.483.647 (int32.MaxValue). Lưu ý rằng giá trị tối đa cho một giá trị ngày sẽ khác với giá trị bạn có thể mong đợi từ cơ sở dữ liệu. Date.MaxValue không bằng SQL DateTime hoặc SmallDateTime lớn nhất. Nói chung, giá trị tối đa của một loại giá trị không bao giờ được sử dụng trong thực tế, trong khi trong trường hợp của một byte, giá trị tối thiểu (0) được sử dụng thường xuyên. –

+3

Carter, có một số cách giải quyết, không ai trong số đó được chấp nhận trong độ tuổi của các loại nullable. ;) –

-2

Loại dễ vỡ được giới thiệu trong .net 3.0, chúng có thể được sử dụng với bộ dữ liệu. Bạn khai báo một int nullable như thế này int? myNullableInt = null Dưới đây là một liên kết đến bài viết MSDN: Nullable Types C#

Cá nhân, tôi muốn tránh xa null trong cơ sở dữ liệu ở nơi đầu tiên (nếu bạn có luxry để làm điều này). NULL thực sự ở đó để cho phép trạng thái "Không xác định" hoặc "Không xác định". Rất hiếm khi gặp phải vấn đề này, ví dụ một trường String chứa họ sẽ thường được đặt thành nullable, trong khi mặc định là "" sẽ là một lựa chọn tốt hơn nhiều. Đặt null vào cơ sở dữ liệu làm cho mọi thứ không cần thiết khó khăn Null Values In Databases, ngoài ra nó truyền null vào mã và bạn phải làm việc để tránh ngoại lệ tham chiếu null.

Thật không may, có rất nhiều nội dung xấu được viết trên Internet về DB (chẳng hạn như sử dụng quá mức null khi đang OK). Những quan điểm này thường là bởi những người thực sự không hiểu lý thuyết đằng sau chúng, một ví dụ điển hình khác là một DB không có quan hệ "vì nó linh hoạt hơn/nhanh hơn để xử lý chúng trong mã". Điều này có nghĩa là dev phải viết lại chức năng [tầng cơ sở dữ liệu] hiện có mà cơ sở dữ liệu không tránh khỏi xử lý hiệu quả hơn và có độ tin cậy cao hơn nhiều. Tôi nói không thể tránh khỏi như, tất nhiên, các dev làm lại viết là tái thực hiện các công cụ mà Oracle/Microsoft/Bất cứ ai đã có các đội lớn chi tiêu rất nhiều thời gian tối ưu hóa vv Tuy nhiên, như vậy thường xuyên, bạn thấy ai đó ủng hộ này như một bản thiết kế. Anh chàng này thực sự hiểu cơ sở dữ liệu, DBDebunkings ông đã dành rất nhiều thời gian cố gắng để debunk rất nhiều arugments vô nghĩa mà có cơ sở dữ liệu quan hệ từ nguồn gốc lý thuyết của họ.

+8

Tôi đã không yêu cầu một bài giảng về những tệ nạn của null. Nghe nó 1000 lần. Tôi đang tìm kiếm một cách dễ dàng để làm cho nullables làm việc với các tập dữ liệu mạnh mẽ gõ. Có lẽ một phương pháp mở rộng hoặc tương tự. Và, nullables được giới thiệu trong .net 2, không phải là 3. –

+0

Làm thế nào thô lỗ. OK Tôi đã nhận được phiên bản khung sai nhưng điều đó hầu như không quan trọng, những gì tôi nói vẫn là viết tắt. Tôi không chính xác là một noob, tôi đã. Kể từ phiên bản 1.0 beta. Tiếc là các bài giảng không có. –

+5

Keith, không cố tỏ ra thô lỗ, chỉ là bạn trả lời một câu hỏi mà tôi không hỏi. –

-1

Tôi không chắc tại sao var x = !IsMyFieldNull() ? MyField : null (hoặc tương tự) là một cơn đau đầu như vậy.

Tôi cho rằng bạn có thể viết một wrapper xung quanh SqlDataReader để bẫy những giá trị null bằng cách nào đó khi bạn đọc dữ liệu vào DataTable của bạn, hoặc bạn có thể viết tương đương với .TryParse() cho các truy vấn của bạn: một cái gì đó tốt đẹp và đóng gói như:

var x = myDataTable.TryParse(myField); 

nơi .TryParse là một phương pháp mở rộng tìm kiếm cái gì đó như:

public static TryParse(DataRow myField) 
{ 
    if(!myField == DbNull) //Or similar 
     return myField.Value; 
} 

này là, như bạn có thể thấy, về cơ bản pseudo-code thô, nhưng bạn sẽ có được ý tưởng. Viết mã của bạn một lần, sau đó gọi nó là một phương thức mở rộng.

+0

Allen, vấn đề là độ dài của một kịch bản thế giới thực: var x = MyDataTable.IsMyfieldNull()? (Int?) Null: (int?) MyDataTable.MyField; Bây giờ lặp lại 5 lần cho 20 bảng với 20 cột trong mỗi bảng. Không vui vẻ;) Ồ, đừng quên mã cần thiết để chuyển nhượng. –

7

Nếu bạn đang sử dụng Net 3.5 hoặc cao hơn, có thể là những phần mở rộng có thể được sử dụng cho bạn: http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.field.aspx

Theo tài liệu, nó hỗ trợ đầy đủ các loại nullable. Nó cho phép bạn sử dụng các cấu trúc như

MyRow.Field<int?>("MyField") 

và nếu bạn gán nó đến hoặc từ một biến hiện có của đúng loại, trình biên dịch có thể suy ra các loại tự động và bạn có thể bỏ qua Bộ xác định kiểu, làm cho nó càng ngắn như

int? myVar = MyRow.Field("MyField"); 
MyRow.Field("MyField") = myVar; 

Vẫn chưa hoàn hảo, nhưng dễ đọc hơn nhiều so với việc sử dụng IsMyFieldNull() v.v. ở mọi nơi.

Oh và nếu bạn muốn trở thành thêm về mặt an toàn liên quan đến tên cột lỗi chính tả, bạn có thể sử dụng những thứ như

MyRow.Field(MyTable.MyFieldColumn) 

Đừng quên để thêm một tham chiếu đến System.Data.DataSetExtensions.

+1

Tôi đã sử dụng nó, và nó giúp ích, nhưng nó không được đánh máy mạnh. Im tìm kiếm datatables mạnh mẽ gõ cho phép loại trường nullable (cho các loại giá trị) –

+0

Tôi đồng ý. Tôi cũng đồng ý rằng nó sẽ rất tốt đẹp nếu họ bao gồm một cái gì đó cho nó trong một phiên bản Visual Studio sắp tới. Đây là gần nhất tôi đã sử dụng các công cụ hiện tại.Tôi đã được nhìn vào khuôn mẫu T4 nhưng trông giống như quá nhiều công việc cho những gì nó có giá trị (với tôi). –

+0

có, rất khó để biện minh cho việc xây dựng lại toàn bộ công cụ tạo bộ dữ liệu chỉ để thêm một tính năng. (vâng, tôi cũng đã xem xét nó;) –

0

Bạn có thể thực hiện việc này: đặt AllowDbNull thành true, nếu không được đặt; DefaultValue vẫn còn trên; NullValue vẫn còn trên (Ném ngoại lệ). Sau đó, từ mã khi bạn muốn thiết lập để null một cột bạn có thể sử dụng được xây dựng trong phương pháp Set_Column_Null(). Hãy xem ví dụ của tôi:

if (entry.PosX.HasValue) 
    newRow.PosX = entry.PosX.Value; 
else 
    newRow.SetPosXNull(); 
0

Tôi chỉ phải tìm một giải pháp cho việc này. Tôi cần phải thay đổi một số mã cũ cho một trang web, được viết cho ASP.NET 2.0. Trang sử dụng Telerik RadMenu, một điều khiển menu. Thành phần này yêu cầu các phần tử gốc có giá trị DBNull thích hợp (cho các parentID). Vì vậy, khi tôi biên soạn mã cũ, thành phần RadMenu đã cho tôi rất nhiều vấn đề. Ngoại lệ đầu tiên liên quan đến Ràng buộc, sau đó nó không hiểu được yếu tố nào là yếu tố gốc và toàn bộ điều trông khủng khiếp.

Nhưng tôi đã giải quyết nó và đây là những gì làm việc cho tôi.

Trong trang Properties của cột ParentID trong thiết kế Bảng Adapter, tôi đã sử dụng: - AllowDBNull: true - DefaultValue: -1 (-1 là một giá trị mà không xảy ra thường cho cột đó) THe NullValue -property ở lại "Ném ngoại lệ" vì nó không thể thay đổi cho tôi.

Và trong mã sử dụng các giá trị từ bộ điều hợp bảng, tôi đã sử dụng cấu trúc này (VB.Mã NET, không phải C#, vì câu hỏi này được gắn thẻ):

Dim MenuBarTable As DAL.Page.MenuBarDataTable 'The Table Adapter 
MenuBarTable = PageObj.GetMenuBar() 'The generated Get function 
MenuBarTable.ParentIDColumn.AllowDBNull = True 

    For Each row As Page.MenuBarRow In MenuBarTable.Rows 
     If row.IsParentIDNull() Then 
      row.SetParentIDNull() 
     End If 
    Next 

Mã được tạo cho bộ điều hợp bảng tạo hai chức năng cho mỗi cột cho phép DBNULL. Chúng có nghĩa là được sử dụng khi giao dịch với NULL, nhưng nó là một giải pháp vụng về của Microsoft. Điều xảy ra đằng sau hậu trường là bộ điều hợp bảng sẽ xuất ra DefaultValue của cột thay vì NULL từ hàm Get-function. Tôi gọi đó là "mô phỏng NULL" hoặc "giả mạo NULL".

Hàm IsParentIDNull() thực sự sẽ kiểm tra xem hàng có chứa "NULL giả" này không, ví dụ: DefaultValue của cột, và khi đó, tôi chèn một DBNull thích hợp bằng cách sử dụng hàm SetParentIDNull().

Giải pháp này làm việc cho tôi, nhưng không phải là rất thanh lịch, cũng không phải là rất hiệu quả, nhưng nó có thể giúp đỡ cho người khác, tôi hy vọng.

Các vấn đề liên quan