tags:

views:

247

answers:

4

At the moment I'm trying to create a kind of model in vb.net which can be used to create/fetch database entrys.

I created a main class Model with a shared function to fetch the datasets, e.g. Model.find(). Now I'd like to create Classes which inherit the main Model-Class, e.g. a separate one for users: UserModel.find() => "SELECT * FROM users".

What I need now is to find a way to tell the Class which table it should use. I thought about an abstract String "table" which is a constant in each "child-model", but how could this be implemented as it's not possible to override shared members?

Thanks in advance!

Edit: Maybe this will make it a little clearer what I mean:

Public Class Model
Public Shared _controller As Controller

Public Shared table As String
Protected Shared tableFields As String()
Shared reader As Npgsql.NpgsqlDataReader

Public Shared Function find()
    Dim a As ArrayList = New ArrayList

    'Test if the tablefields are already known to the class, if not, get them

    If tableFields Is Nothing Then
        getTableFields()
    End If

    Dim query As String = "SELECT " + String.Join(", ", tableFields) + " FROM " + table
    reader = _controller.executeReader(query)
        While reader.Read
            o = New Model
            Dim v As New Hashtable
            For Each field In tableFields
                v(field) = reader(field)
            Next
            o.values = v
            a.Add(o)
        End While
        reader.Close()
        Return DirectCast(a.ToArray(GetType(Model)), Model())
End Function

Public values As Hashtable

Public Sub New()
End Sub

End Class

So I want a shared method which finds all database entries and gives back an array of instances of its own type, e.g. Model(). That's why I wanted to keep the find-method shared and not bound to an instance.

A: 

You could make your main class abstract and each subclass will have to return its "own" table name via its own implementation (e.g. getTableName). This way, you would only have to maintain you method logic in the main class.

thelost
A: 

It is common to use the Singleton design pattern in such cases: create an instance method, overridden by inheriting classes. Each inheriting class should have that instance method return a Singleton object related to that class.

Here is one way of doing it:

MustInherit Class BaseClass
    Public MustOverride Function getTableName() As String
End Class

Class Class1
    Inherits BaseClass
    Private Shared TableName As String = "myTable1"
    Public Overrides Function getTableName() As String
        Return TableName
    End Function
End Class

Class Class2
    Inherits BaseClass
    Private Shared TableName As String = "myTable2"
    Public Overrides Function getTableName() As String
        Return TableName
    End Function
End Class

EDIT: a whole different approach. You can have the base class hold some dictionary, which relates class types (or type names) with the correct table:

Class BaseClass
    Private Shared myDictionary As New Collections.Generic.Dictionary(Of Type, String)
    Friend Shared Sub RegisterType(ByVal childType As Type, ByVal tableName As String)
        myDictionary.Add(childType, tableName)
    End Sub
    Public Shared Function getTableName(ByVal childType As Type) As String
        Return myDictionary.Item(childType)
    End Function
End Class
Class Class1
    Shared Sub New()
        BaseClass.RegisterType(GetType(Class1), "table1")
    End Sub
End Class
Class Class2
    Shared Sub New()
        BaseClass.RegisterType(GetType(Class2), "table2")
    End Sub
End Class
M.A. Hanin
That's what I tryed before, the problem is, I need the table name in the shared method and can't declare a public shared function as overridable/mustoverride. Or did I misunderstand your code?
stex
The getTableName function is not shared - it is a "normal" instance method, which must be overridden by sub-classes. Every sub-class that overrides this method returns a private shared variable (or a class-level constant, if possible). Every instance of Class1 will return the same TableName, despite the fact that getTableName is an instance method and not a shared method.The idea is to make an instance method act as a shared method when triggered (return the same value/reference, no matter which instance's method is invoked), while keeping the benefits of overriding in sub-classes.
M.A. Hanin
Yes, I understand. But I don#t want to create an instance of Class1, I want Class1 to know about the table name without creating an object.
stex
I've proposed another model, using shared constructors. I hope this is closer to what you're looking for.
M.A. Hanin
A: 

Shared (static) objects or object members can't be inherited or overrided. Inheritence is for instance of an object. Since you do not have to instantiate a static class you can't inherit from it. The same with the methods. A static method shouldn't be virtual (Overridable in VB) as it defines a method that perform tasks with no instance of the class. Then this makes it impossible to use instance fields or properties within a static (Shared in VB) method. This is a bad design trying so.

In fact, every static (Shared) classes should be marked as NotInheritable in VB, and defining the default empty constructor only. This is a leak from VB in regards of OOP concepts.

Will Marcouiller
A: 

I think you could use Generics. Here I´ve pasted an example

All the classes in your domain could inherit from Entity class

Public MustInherit Class Entity

    '...

End Class

Your Model class, with your method Find

Public Class Model

    Public Shared Sub Find(Of T As Entity)()

        ' You could know the name of T to find the table

        Dim tableName As String = GetType(T).Name

        '... 

    End Sub

End Class

One class of your domain, for example: User class

Public Class User
    Inherits Entity

    ' ...

End Class

And finally, an example of how could you instantiate the Find method

Model.Find(Of User)()

'...

I dunno if this is what you mean, do you find this helpfull?

Javier Morillo