0

I was given a library with generic data objects in it, Projects, Tables, Rows and Fields. In my program I have a single Project called Building, its Table 1 contains "Units", and Field 1 of Table 1 is "Unitname". So what I did was...

Public Class Unit
  Private myRow As Row
  Public Sub New(ByRef R as Row)
    myRow = Row
  End Sub
  Public Function Unitname() as String
    Return myRow.Fields(1)
  End Function
  ... etc ...
End Class

That doesn't look so bad does it? But I don't have Unit objects loaded, I have Rows. So then I also have to make a another class...

Public Class Building
  Private myProj as Project
...
  Public Function Units() As List(Of Unit)
    Dim ans as New List(Of Unit)
    For Each R In myProj.Tables(1).Rows
      ans.Add(new Unit(R))
    Next
    Return ans
    ' or I could use myProj.Tables(1).Rows.ConvertTo(Of Unit)
 End Function
 ...etc...

And of course I have to make the list of Buildings so I can get to the list of Units, and the dozens of other lists and accessors, turning into thousands of lines of code who's only purpose is to make one set of objects that points to another.

It works, and I know shipping is a feature. But what I really want to do is make a Unit that looks like...

Public Class Unit
  Inherits Row
  ...
End Class

Then I would "reverse cast" the List(Of Row) into a List(Of Unit). This would not only eliminate a lot of code, it would eliminate dangling pointers, reduce memory a whole lot, and eliminate a set-up set that might take some time. Theoretically possible, there's no difference except code, but I don't see a way to do it in VB.Net.

In Obj-C this is called swizzling (and/or extensions), and I think Java has a similar concept. I suspect that ADO.Net has to do something like this? Is there some sort of "wrap this in that" functionality I'm missing?

Maury Markowitz
  • 9,082
  • 11
  • 46
  • 98

2 Answers2

0

Save yourself a lot of time and use a DataSet. For database apps, object-oriented programming doesn't work too well. DataSets can be in-memory only and don't need a database engine.

Dim dsProject As New DataSet("Project")
Dim dtUnits As New DataTable("Units")
dtUnits.Columns.Add("Unitname", GetType(String))
dtUnits.Columns.Add("Address", GetType(String))
dsProject.Tables.Add(dtUnits)
dtUnits.Rows.Add("Unit 1", "1 Test Street")
dtUnits.Rows.Add("Unit 2", "2 Sample Avenue")
dtUnits.Rows.Add("Unit 3", "3a Demo Road")

Dim drMatch() As DataRow = dtUnits.Select("Unitname='Unit 1'")
If drMatch.GetUpperBound(0) >= 0 Then
  MsgBox(drMatch(0).Item("Address"))
Else
  MsgBox("No matching record")
End If
SSS
  • 4,807
  • 1
  • 23
  • 44
  • Perhaps I'm misunderstanding this example... the problem I have to solve is that the data is already fully read in, and passed back to me as a bunch of List(Of String). It appears using this solution would have to copy those items into the DataRow, which is precisely what I'm doing with my own classes. Am I missing some magic here? – Maury Markowitz Jan 19 '15 at 22:07
  • Yes, I'm suggesting you abandon your own custom object model, and instead use the built-in `System.Data` objects. The advantage is that you don't need to write as much code, and better integration with the built-in data controls etc. You might not want to do that, of course. – SSS Jan 19 '15 at 23:15
  • I'd also recommend you abandon the generic object library too, since the names of the objects (table, row, field) imply that they are mimicking a database object model. – SSS Jan 19 '15 at 23:17
  • That is precisely what it is doing - it is using XLS files to mimic a database. Now before you say "why don't you just...", the answer is that this library is between 1,000 and 5,000 times as fast as MS's solution. Not kidding, trust me, we tested. – Maury Markowitz Jan 20 '15 at 17:42
0

If you don't want to use DataSets, you could try a shared converter function:

  Class unit
    Inherits row

    Public Property UnitName() As String
      Get
        Return fields(1)
      End Get
      Set(ByVal value As String)
        fields(1) = value
      End Set
    End Property

    Shared Function UnitToRow(u As unit) As row
      Return DirectCast(u, row)
    End Function

    Shared Function RowToUnit(r As row) As unit
      Dim u As New unit
      u.fields = r.fields
      Return u
    End Function

  End Class

  Sub usage()
    Dim lstR As New List(Of row) '<--- source data

    Dim lstU As List(Of unit) = lstR.ConvertAll(New Converter(Of row, unit)(AddressOf unit.RowToUnit))
    MsgBox(lstU(0).UnitName)

    lstU(0).UnitName = "xxx"

    Dim lstR2 As List(Of row) = lstU.ConvertAll(New Converter(Of unit, row)(AddressOf unit.UnitToRow))
    MsgBox(lstR2(0).fields(1))

  End Sub
SSS
  • 4,807
  • 1
  • 23
  • 44