2013-03-05 76 views
2

我今天嘗試做一些實驗。我有一個應用程序使用無類型的數據表作爲模型實體。 他們都做出這樣的:未鍵入強類型數據表

Imports System.Data 
Imports System.Runtime.Serialization 
Imports System.ComponentModel 

<DesignerCategory("Code"), system.Serializable()> 
Partial Public Class SomeTable1 
    Inherits DataTable 

#Region 
    Public Const TABLE_NAME As String = "SomeTable1" 

    Public Const FIELD_SomeField1 As String = "SomeField1" 
    Public Const FIELD_SomeField2 As String = "SomeField2" 
#End Region 

    Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 
     MyBase.New(info, context) 
    End Sub 

    Public Sub New() 
     MyBase.New() 

     With Columns 
      .Add(FIELD_SomeField1, GetType(System.String)).DefaultValue = String.Empty 
      .Add(FIELD_SomeField2, GetType(System.Double)).DefaultValue = 0 
     End With 

     Dim keys(1) As DataColumn 
     keys(0) = Columns(FIELD_SomeField1) 
     TableName = TABLE_NAME 
     PrimaryKey = keys 
    End Sub 
End Class 

我目前正與EF工作,所以在我的球藝,我寫了這樣的事情(是的,這是VB):

Partial Public Class SomeTable1 
    Inherits DataTable 

    <Key()> 
    Friend Property SomePK1 As DataColumn 

    <Required(ErrorMessage:="SomeField1 is required.")> 
    <DataType(DataType.Text)> 
    Friend Property SomeField1 As DataColumn 

    <Required()> 
    <DataType(DataType.DateTime)> 
    Friend Property SomeField2 As DataColumn 
    ... 

    Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 
     MyBase.New(info, context) 
    End Sub 

    Public Sub New() 
     MyBase.New() 

     SomeField2 = Date.Now 
    End Sub 
End Class 

我是在做夢上使之與前者相當,並且與當前的數據引擎完全兼容。

然後類型轉換錯誤(系統日期datacolumn)打破了我的希望。我必須承認,這是一個艱難的週末:)

因此,在我完全放棄改變之前,有沒有什麼方法可以編寫一個Typed數據表,因此它等同於上面的代碼,但帶有一些新的好東西? 這是如此古老的編程方式,我無法在網上找到任何東西。 在此先感謝。

+0

如果我讀了這個權利,我想我會創建一個包裝庫類似的層。它會將dt對象與o/r映射器一起轉換爲您自己創建的新dto對象。代碼庫中的更高層使用這個存儲庫對象。中提琴,你已經鍵入集合。讓EF成爲第二種方式,也許你也將它傳遞到相同的存儲庫結構(分離的接口),並讓EF實現的更高級別也是未知的。 – Independent 2013-03-06 19:03:09

+0

@Jonas,多麼有趣。但我很抱歉,我無法完全跟隨你。包裝知識庫般的圖層? 只是假設你正在和一些曾經使用asm/as400/cxm並且被迫去VB6然後VS的老人交談...並且有時候不能完全理解C#的東西(JAhJAh) 請告訴我更多。 – Sergio 2013-03-07 17:33:37

回答

0

我發現怎麼做我想要的。也許涉及一些工作,但它的工作。 知道這是一種過時的做事方式,我在那裏張貼,所以像我這樣的被迫維護舊程序的人可以受益。

做類型化的DataTable的模板如下:

Imports System.Data 
Imports System.ComponentModel 
Imports System.Runtime.Serialization 
Imports System.Diagnostics 

'''<summary> 
'''Represents the strongly named DataTable class. 
'''</summary> 
<Global.System.Serializable(), _ 
Global.System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")> _ 
Partial Public Class tblMyTable 
    Inherits TypedTableBase(Of tblMyTableRow) 

    'Those are the StoredProcs names for (MANUAL) CRUD operations that the DBContext wrapper uses. (yuck! I hate thousands of them) 
    'Public Const COMMAND_SAVE As String = "sp_MyTable_Save" 
    'Public Const COMMAND_DELETE As String = "sp_MyTable_Delete" 
    'Public Const COMMAND_LOADBY_ID As String = "sp_MyTable_LoadBy_Id" 

    'Those are constants I maintain for untyped (but somewhat strong) compatibility 
    Public Const FIELD_pID As String = "pID" 
    Public Const FIELD_SomeOther As String = "SomeOtherField" 

    'Basic CRUD, uses company data as the app hot swapps DBs (one for company) 
    'Public Function Save(ByVal company As DataRow) As Short 
    ' Return New Base(company).Update(Me, COMMAND_SAVE, COMMAND_DELETE) 
    'End Function 

    'Public Sub LoadByID(ByVal company As DataRow, Id As Integer) 
    ' Me.Rows.Clear() 
    ' Me.Merge(New Base(company).FillDataTable(Of tblMyTable)(COMMAND_LOADBY_ID, Id)) 
    'End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Private Sub InitClass() 
     Me.columnpID = New DataColumn(FIELD_pID, GetType(Integer), Nothing, MappingType.Element) With 
        {.AllowDBNull = False, .ReadOnly = True, .Unique = True, 
        .AutoIncrement = True, .AutoIncrementSeed = -1, .AutoIncrementStep = -1} 
     MyBase.Columns.Add(Me.columnpID) 
     Me.columnSomeOtherField = New DataColumn(FIELD_SomeOther, GetType(String), Nothing, MappingType.Element) With 
          {.MaxLength = 5, .AllowDBNull = False, .DefaultValue = String.Empty} 
     MyBase.Columns.Add(Me.columnSomeOtherField) 
    End Sub 

    Private columnpID As DataColumn 
    Private columnSomeOtherField As DataColumn 

    <DebuggerNonUserCodeAttribute()> 
    Public Sub New() 
     MyBase.New() 
     Me.TableName = "tblMyTable" 
     Me.BeginInit() 
     Me.InitClass() 
     Me.EndInit() 
    End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Friend Sub New(ByVal table As DataTable) 
     MyBase.New() 
     Me.TableName = table.TableName 
     If (table.CaseSensitive <> table.DataSet.CaseSensitive) Then 
      Me.CaseSensitive = table.CaseSensitive 
     End If 
     If (table.Locale.ToString <> table.DataSet.Locale.ToString) Then 
      Me.Locale = table.Locale 
     End If 
     If (table.Namespace <> table.DataSet.Namespace) Then 
      Me.Namespace = table.Namespace 
     End If 
     Me.Prefix = table.Prefix 
     Me.MinimumCapacity = table.MinimumCapacity 
    End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Protected Sub New(ByVal info As Global.System.Runtime.Serialization.SerializationInfo, ByVal context As Global.System.Runtime.Serialization.StreamingContext) 
     MyBase.New(info, context) 
     Me.InitVars() 
    End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Public ReadOnly Property pIDColumn() As DataColumn 
     Get 
      Return Me.columnpID 
     End Get 
    End Property 

    <DebuggerNonUserCodeAttribute()> 
    Public ReadOnly Property SomeOtherFieldColumn() As DataColumn 
     Get 
      Return Me.columnSomeOtherField 
     End Get 
    End Property 

    <DebuggerNonUserCodeAttribute(), Browsable(False)> 
    Public ReadOnly Property Count() As Integer 
     Get 
      Return Me.Rows.Count 
     End Get 
    End Property 

    <DebuggerNonUserCodeAttribute()> 
    Default Public ReadOnly Property Item(ByVal index As Integer) As tblMyTableRow 
     Get 
      Return CType(Me.Rows(index), tblMyTableRow) 
     End Get 
    End Property 

    <DebuggerNonUserCodeAttribute()> 
    Public Overrides Function Clone() As DataTable 
     Dim cln As tblMyTable = CType(MyBase.Clone, tblMyTable) 
     cln.InitVars() 
     Return cln 
    End Function 

    <DebuggerNonUserCodeAttribute()> 
    Protected Overrides Function CreateInstance() As DataTable 
     Return New tblMyTable() 
    End Function 

    <DebuggerNonUserCodeAttribute()> 
    Friend Sub InitVars() 
     Me.columnpID = MyBase.Columns(FIELD_pID) 
     Me.columnSomeOtherField = MyBase.Columns(FIELD_SomeOther) 
    End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Public Function NewtblMyTableRow() As tblMyTableRow 
     Return CType(Me.NewRow, tblMyTableRow) 
    End Function 

    <DebuggerNonUserCodeAttribute()> 
    Protected Overrides Function NewRowFromBuilder(ByVal builder As DataRowBuilder) As DataRow 
     Return New tblMyTableRow(builder) 
    End Function 

    <DebuggerNonUserCodeAttribute()> 
    Protected Overrides Function GetRowType() As Global.System.Type 
     Return GetType(tblMyTableRow) 
    End Function 

    <DebuggerNonUserCodeAttribute()> 
    Public Sub RemovetblMyTableRow(ByVal row As tblMyTableRow) 
     Me.Rows.Remove(row) 
    End Sub 

End Class 

'''<summary> 
'''Represents strongly named DataRow class. 
'''</summary> 
Partial Public Class tblMyTableRow 
    Inherits DataRow 

    Private tabletblMyTable As tblMyTable 

    <DebuggerNonUserCodeAttribute()> 
    Friend Sub New(ByVal rb As DataRowBuilder) 
     MyBase.New(rb) 
     Me.tabletblMyTable = CType(Me.Table, tblMyTable) 
    End Sub 

    <DebuggerNonUserCodeAttribute()> 
    Public Property pID() As Integer 
     Get 
      Return CType(Me(Me.tabletblMyTable.pIDColumn), Integer) 
     End Get 
     Set(value As Integer) 
      Me(Me.tabletblMyTable.pIDColumn) = value 
     End Set 
    End Property 

    <DebuggerNonUserCodeAttribute()> 
    Public Property SomeOtherField() As String 
     Get 
      Return CType(Me(Me.tabletblMyTable.SomeOtherFieldColumn), String) 
     End Get 
     Set(value As String) 
      Me(Me.tabletblMyTable.SomeOtherFieldColumn) = value 
     End Set 
    End Property 
End Class 

這就是你需要的。也許它可能會減少,但數據集函數不會按預期工作。

如果你想要的代碼,由ID(VS2010了)自動爲您生成您必須遵循這些步驟:

  1. 在服務器資源管理器,創建連接到您最喜愛DB
  2. 上單擊鼠標右鍵選擇您的項目頂部並選擇添加新元素。
  3. 只需選擇數據集對象模板,名稱就不相關。它將在設計師視圖中打開。
  4. 從數據庫中選取表格並拖動到數據集設計器。
  5. 然後...看看頂部的類選擇器。
  6. 展開並找到[yourTableName] Datatable。點擊它。
  7. 它將跳轉到DataSet1.designer.vb(cs)文件中的所述類。
  8. 下一個類是行定義。只需將它們複製粘貼到一個新的類文件中即可。
  9. 如果你想要一個更完整的數據表對象,下一個類 下面的行類定義了事件,而它的代表只是在 表的def上面。

很簡單,我測試它與其餘程序一起工作,即使用無類型。 也許它會像拋光turd,但我想添加數據註釋某處作爲一些客戶端驗證,如在EF中。也許可以替換它們的列構造函數參數。 (但我caaan't)

好運。

+0

也可以看看這個其他的[問題](http://stackoverflow.com/questions/1203915/handcrafted-strongly-typed-ado-net-datatable-can-it-be-cleaner)爲最低限度的方法。 – Sergio 2013-03-08 11:21:45

0

不知道我完全以下,但它看起來像你定義FIELD_SomeField2爲雙

(這條線第一個片段)

.Add(FIELD_SomeField2, GetType(System.Double)).DefaultValue = 0 

但後來我看到你定義SomeField2作爲您的第二個片段中的日期時間。

<Required()> 
<DataType(DataType.DateTime)> 
Friend Property SomeField2 As DataColumn 

所以也許只是一個類型不匹配......

+0

哦,是的。我從兩個不同的類中選擇了示例代碼。我正在工作的最上面的一個,以及我的試驗下面的那個。但我發現如何做到這一點。我會做一些測試,明天發佈。 – Sergio 2013-03-06 18:40:40