2013-03-05 26 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