Entity Framework (VB.NET)

Associate
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
I'm new to EF but have some experience with ado.net but more with DAO and ADO (yes I'm old school).

I'm in a position where I have some time to deliver a new solution so I'm going to take the opportunity to learn EF.

It's basically going to be a custom error logging system for one of our core systems.

In simple terms it is going to be a SQL back end with a WPF front end (yes I'm learning that too)

My general design style is to retrieve required data at load time and hold this in various classes in the app. So for instance if I need to retrieve data based on a user ID from a table I would use a datareader (or connectionstring) and either add the results to a datatable or array and then populate the class from the datatable or array.

I don't really understand where EF would store the data say when you run the following:

Using userContext As New userEntities
Dim qry = From s In userContext.tUsers _
Where (s.windowsID = LCase(Environment.UserName))
End Using

qry will be destroyed when the block ends so do I have to add the results to a class or are the results actually already held in userEntities.tUser, if so I want to retrieve them, say by doing something like:

Dim username as string = tUser.UserName is that in essence calling a db query or is it fact referring to a derived class?

As you can see I'm confused, things used to be so much easier to conceptualize than they are now.
 
Last edited:
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
OK been playing around and I think I have figured out the concept.

I think the issue I had was that I thought you would use EF to replace my classes.

Anyway one of the things I like to do is to hold the data for combo boxes and other controls in dictionaries or arrays (usually dictionaries).

I know I can loop through the results of my linq query in ef however is there anyway to add it direct to a dictionary? The examples I have seen are in c# and it doesn't seem to translate to vb.net. It simply doesn't compile.

Any tips?

Public Class clsDept

Private mDepartments As Dictionary(Of Integer, String)

Public Sub New()

Using db As New pResolveEntities

Dim dept = (From a In db.tDepts
Where a.Live = 1
Order By a.DeptName
Select a.ID, a.DeptName).ToDictionary(a.ID, a.DeptName)


End Using

End Sub
End Class
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
OK have managed to get it into a style I understand but I would still prefer if I could go straight to .todictionary for cleanliness stakes:


Private mDepartments As Dictionary(Of Integer, String)

Public Sub New()

Try

Using db As New pResolveEntities

Dim depts = From a In db.tDepts
Where a.Live = False
Order By a.DeptName
Select a.ID, a.DeptName

Dim mDepartments = New Dictionary(Of Integer, String)

If depts.Count > 0 Then

For Each dept In depts.ToList
mDepartments.Add(dept.ID, dept.DeptName)
Next
Else
With Err()
.Clear()
.Number = 9999
.Description = "No Data"
End With
Err.Raise(9999)
End If


End Using

Catch ex As Exception

MsgBox(ex.Message)

End Try

End Sub
End Class
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
Thanks I have looked at mvvm and it blows my brain so one step at a time I think:

Code:
Public Sub New()

        Try

            Dim db As New pResolveEntities

            Dim depts = From a In db.tDepts
                        Where a.Live = True
                        Order By a.DeptName
                        Select a.ID, a.DeptName

            mDepartments = New Dictionary(Of Integer, String)

            For Each dept In depts
                mDepartments.Add(dept.ID, dept.DeptName)
            Next

            If mDepartments.Count = 0 Then
                With Err()
                    .Clear()
                    .Number = 9999
                    .Description = "No Data"
                End With
                Err.Raise(9999)
            End If
        Catch ex As Exception
            MsgBox(ex.Message)
        Finally
            Dim db = Nothing

        End Try


    End Sub

I have amended the code to drop the .tolist and as you say it works and I now simply check the number of items in the dictionary instead of enumerating the query again. Thanks for the tip.

I need to check this to make sure there are actually items to populate a combo box with.

As you say I'm using a dictionary to populate a combobox which in wpf has took me the best part of an hour to half figure out how to do it.

I need the key as this is is what will be returned to a different table in the db, I never store the display value in a record.

Code:
Me.cbTest.ItemsSource = dept.Departments
        Me.cbTest.DisplayMemberPath = "Value"
        Me.cbTest.SelectedValuePath = "Key"

This "seems" to work however I cannot retrieve the value of the ket from the SelectionChanged event, in fact I cannot return anything from it.

Winforms it would just be me.cbtest.value

EDIT: nvm it is .selectedvalue
 
Last edited:
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
Thanks again I guess you mean a class rather than type? Either way though surely if I create a custom object to hold the value then in effects it's going to be a list of integers and a list of strings anyway? I'm sure it's cleaner but not sure it's any easier, I'll have a play and see what I come up with. To be fair I would normally populate a combo box with an array rather than a dictionary but arrays seem renowned upon nowadays.
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
Well I managed to do something similar, but I bind the combo box to the class itself and using the generic collectionbase class to add it to the combobox keeps it nice and clean:

Code:
Public Class clsDept
    Inherits CollectionBase


    Public Sub New()

        Using db As New pResolveEntities
            Try
                Dim depts = From a In db.tDepts
                            Where a.Live = True
                            Order By a.DeptName
                            Select a.ID, a.DeptName

                For Each dept In depts
                    Me.InnerList.Add(dept)
                Next

                If Me.InnerList.Count = 0 Then
                    With Err()
                        .Clear()
                        .Number = 9999
                        .Description = "No Data"
                    End With
                    Err.Raise(9999)
                End If
            Catch ex As Exception
                MsgBox(ex.Message) 'replace with error function and email

            End Try
        End Using

    End Sub
End Class

And on the load event of the form:

Code:
Me.cbTest.ItemsSource = New clsDept
Me.cbTest.DisplayMemberPath = "DeptName"
Me.cbTest.SelectedValuePath = "ID"

Simple when you know how:)
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
OK so I have another thing I can't get my head around.

In vb6 you could declare an instance of an object as public

So

Code:
 Public user as cUser

You could then instantiate that object anywhere within your project using:

Code:
 Set user as new cUser

That would mean for instance you could create the user object at run time and its members and properties would be available to all other classes and modules within the project.

I cannot see to do this using wpf and vb.net.

What I have is wpf form which is basically a splashscreen, behind that a number of validation tasks will occur, such as making sure that a db exists and that the user has authority to access the application.

This splashscreen form is bound to a class called InitialValidation like this:

Code:
Public Class InitialValidation

    Private Sub InitialValidation_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)

        Dim user As New cUser

    End Sub

    Public Sub New()

        InitializeComponent()

    End Sub
End Class

This works fine and the object user is created which looks a bit like this:

Code:
Public Class cUser

    Private pUserID As Integer
    Private pWindowsUserID As String
    Private pUserName As String
    Private pFunctionID As Integer
    Private pFunctionName As String
    Private pLive As Boolean

    Public Sub New()

        Using db As New pResolveEntities
            Try

                Dim qry = From a In db.tUsers
                          Where a.Live = True And a.WindowsUserID = "handaa"
                          Select a

                For Each res In qry
                    pUserID = res.UserID
                    pWindowsUserID = res.WindowsUserID
                    pUserName = res.UserName
                    pFunctionID = res.FunctionID
                    pFunctionName = res.tFunction.FunctionName
                    pLive = res.Live
                Next

                If qry.Count = 0 Then
                    Err.Clear()
                    With Err()
                        .Number = 9999
                        .Description = "No Data"
                    End With
                    Err.Raise(9999)
                End If

            Catch ex As Exception
                MsgBox(Err.Description)

            End Try

        End Using
    End Sub

    Public ReadOnly Property UserName As String
        Get
            Return pUserName
        End Get
    End Property

End Class

I have tried various ways to make the object available throughout the project such as putting a
Code:
Public User as cUser
at the top of the form but I get compile errors, saying not valid in namespace. If I put it at the first line of the class definition it run but I then get an error with it saying dbconnection string cannot be found in appconfig.

I'm sure I'm making the mistake of applying vb6 design decisions to .net but is there a preferred way to do this rather than having to pass the object between forms?
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
Headhurting time: seems I need to declare it is public shared:

Code:
Public Class InitialValidation
    Public Shared user As cUser
    Private Sub InitialValidation_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)

        user = New cUser

and then I can use across the project using something like this:

Code:
MsgBox(InitialValidation.user.UserName)

The limitation of this is that I can only ever have one instance of user. FIne for this object but this method is unlikely to work for my other stuff.
 
Associate
OP
Joined
14 Mar 2007
Posts
1,667
Location
Winchester
Well it won't be available globally (at least the way I understand globally to mean) it will only be available in the project namespace.

I guess it's just habit (and laziness) I think .net forces you to actually know before hand what variables you need for any given view and make sure any classes are only initialized as and when you need that view.

Rather than initializing what you need at start up and just having them available as and when you need them.

I can get around the limitation but it just means I need to think about the application in full before I build it rather than designing it as I write the code.
 
Back
Top Bottom