Using EF with a SQL datastore, the datastore is not updating with the correct data. Here is my code portion for how i create the wrapper object and the relevant function that should update. I think my issue has something to do with the lifecycle of the entity context? But shouldn't re-attaching the object to the context before saving it resolve any issues?
Public Sub New(ByVal UserID As Integer)
Using Context As New RiseDB.RiseDBContainer
MyUser = Context.Users.Find(UserID)
End Using
End Sub
Public Function Save() As Boolean
Using Context As New RiseDB.RiseDBContainer
Context.Users.Attach(MyUser)
Context.SaveChanges()
End Using
Return True
End Function
Protected Overrides Sub Finalize()
If Not IsNothing(Context) Then
Context.SaveChanges()
Context.Dispose()
Context = Nothing
End If
MyBase.Finalize()
End Sub
The function that should set a property:
Public Shared Function PasswordChanged(ByVal UserID As Integer) As Boolean
Dim tmp As New User(UserID)
tmp.IsPasswordReset = False
tmp.Save()
Return True
End Function
Related
Conceptually, I am a little bit lost on Events themselves, so any information here would be helpful.
Specifically, I have a very simple Property Setter which raises an event, and I want to confirm
that this event is raised and also
that the proper parameters have been passes to said event. (although 2. may be unnecessary for this particular event.)
I am trying to contain the overhead in my Unit Testing project, that is, avoid any additional coding in the project being tested.
The code is as follows.
Public Class myItem
Shared Event ItemOpened As EventHandler(Of EventArgs)
.........
Public Property Open() As Boolean
Get
Return mOpen
End Get
Set(ByVal value As Boolean)
mOpen = value
RaiseEvent ItemOpened(Me, New EventArgs)
End Set
End Property
All code is being done in VB.net, which is primary reason why I have not found a good enough resource online for this yet. And also, I am not using a third-party mocking framework such as Nunit or RhinoMock, only MS built in Unit Testing frameworks in VS2012.
Also, similarly, I would like to test FirePropertyChangedNotification() on certain setter methods such as follows....
Public Property myBool() As Boolean
Set(ByVal Value As Boolean)
FirePropertyChangedNotification("myBool")
mViewOnly = Value
End Set
End Property
In which FirstPropertyChangedNotification() is as follows.....
Protected Sub FirePropertyChangedNotification(ByVal propName As String)
If Not Initializing Then
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
RaiseEvent EntityChanged(Me, New PropertyChangedEventArgs(propName))
End If
End Sub
I'm not sure why you want to use Fakes here... You can just use a delegate in you test to subscribe to your event. Now change the property from the test and set a boolean or even place the assert in the delegate.
This is what I'd do in C#, autoconverted to VB.NET (which in my case is very rusty...) This works on my machine. Any improvements from a VB.NET expert are welcome:
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports System.ComponentModel
Namespace UnitTestProject2
Public Class Sut
Implements INotifyPropertyChanged
Public Property StringProperty() As String
Get
Return String.Empty
End Get
Set(value As String)
OnPropertyChanged("StringProperty")
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(ByVal name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
End Class
<TestClass> _
Public Class UnitTest1
<TestMethod> _
Public Sub TestMethod1()
Dim sut As New Sut()
Dim triggered = False
AddHandler sut.PropertyChanged, Sub(o, e)
Assert.AreEqual("StringProperty", e.PropertyName)
triggered = True
End Sub
sut.StringProperty = "test"
Assert.IsTrue(triggered)
End Sub
<TestMethod> _
Public Sub TestMethod2()
Dim sut As New Sut()
Dim triggered = False
AddHandler sut.PropertyChanged, Sub(o, e)
Assert.AreSame(sut, o)
triggered = True
End Sub
sut.StringProperty = "test"
Assert.IsTrue(triggered)
End Sub
End Class
End Namespace
I'm having a hard time understanding why I can't get this transaction to roll back. I have a DataAccess object that handles the connection/transaction. I have a MailingData business object, and a MailingDataAccess object which takes the DataAccess object byRef from the MailingData object and executes a stored procedure. I immediately rollback the update, but it doesn't roll back. I'm guessing this is a scope issue. Help? I was doing byval with dataaccess, but that wasn't working so I changed to byref.
vb.net console app -
code:
Dim da As DataAccess = New DataAccess("mydb")
Try
' business object
Dim mailingData as New MailingData()
' start a transaction
da.StartTransaction()
' do stuff, set properties...
' pass the data access object byref to a method that calls a stored proc
mailingData.UpdateCategorize(da)
' testing, this doesn't roll back the update from the above stored proc
da.RollBackTransaction()
'da.CommitTransaction()
Catch ex As Exception
da.RollBackTransaction()
End Try
My data access object:
Private _database As Database
Private _transaction As Data.IDbTransaction
Private _connection As Data.IDbConnection
Public ReadOnly Property Database() As Database
Get
Return _database
End Get
End Property
Public ReadOnly Property Connection() As IDbConnection
Get
Return _connection
End Get
End Property
Public ReadOnly Property Transaction() As Data.IDbTransaction
Get
Return _transaction
End Get
End Property
Public Sub New()
_database = GetDatabase()
End Sub
Public Sub New(ByVal database As String)
_database = GetDatabase(database)
End Sub
Private Function GetDatabase() As Database
Return DatabaseFactory.CreateDatabase()
End Function
Private Function GetDatabase(ByVal database As String) As Database
Return DatabaseFactory.CreateDatabase(database)
End Function
'-- if not transaction started, start new one.
Public Sub StartTransaction()
If _transaction Is Nothing Then
_connection = _database.CreateConnection()
_connection.Open()
_transaction = _connection.BeginTransaction
End If
End Sub
Public Sub CommitTransaction()
_transaction.Commit()
If Not IsNothing(Connection) Then
Connection.Close()
End If
End Sub
Public Sub RollBackTransaction()
_transaction.Rollback()
If Not IsNothing(Connection) Then
Connection.Close()
End If
End Sub
End Class
mailingData.UpdateCategorize() is defined within the mailingData business object as:
Public Function UpdateCategorize(ByRef da As DataAccess) As Integer
Dim mailingDA As New MailingDataAccess
Return mailingDA.UpdateCategorize(da, Me)
End Function
MailingDataAccess.UpdateCategorize is defined as:
Public Function UpdateCategorize(ByRef da As DataAccess, ByVal clsMailing As MailingData) As Integer
Dim db As Database = da.Database
Dim DbCommand As DbCommand
Dim dbStatus As Integer = 0
DbCommand = da.Database.GetStoredProcCommand("proc_UpdateCategorize")
With db
.AddInParameter(DbCommand, "#pMailingID", Data.DbType.Int32, clsMailing.MailingID)
dbStatus = db.ExecuteNonQuery(DbCommand)
Return dbStatus
End Function
I figured it out, this line:
dbStatus = db.ExecuteNonQuery(DbCommand)
should be:
dbStatus = db.ExecuteNonQuery(DbCommand, da.Transaction)
I have some Linq to SQL table classes that are joined together. I currently have it bound to a treeview using just the LINQ to SQL query. It works, but it doesn't show when stuff is added or removed from the database.
I implemented INotifyPropertyChanged but it isn't updating the treeview.
I also tried using Bindable Linq, but it doesn't seem to make a difference.
I found an example of a way to easily create ObservableCollections without having to create more classes: jimlynn.wordpress.com/2008/12/09/using-observablecollection-with-linq/, (which is kind of important because I have a future project looming that will require interacting with a lot of tables (30 or so) and just creating the Linq to SQL classes is going to be a pain).
Property ModelQuery As ObservableCollection(Of dbModels) = New ObservableCollection(Of dbModels)().PopulateFrom(From mm In tblModels.AsBindable Order By mm.ModelName)
Is this a good way to go, or am I going to have to create a separate ObservableCollection and maintain them both in code. If I'm going to use this binding stuff, I'm really looking for a way to have stuff just linked together so I don't have to update multiple structures whenever a change is made.
Main table:
<Table(Name:="Models")> Public Class dbModels
Implements INotifyPropertyChanged
Private _changed As Boolean
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Public Property Changed() As Boolean
Get
Return _changed
End Get
Set(ByVal value As Boolean)
If _changed <> value Then
_changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Private _ModelID As Integer
<Column(Storage:="_ModelID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ModelID")> _
Public Property ModelID() As Integer
Get
Return Me._ModelID
End Get
Set(value As Integer)
Me._ModelID = value
End Set
End Property
Private _ModelName As String
<Column(Storage:="_ModelName", DbType:="Varchar(200)", Name:="ModelName")> _
Public Property ModelName() As String
Get
Return Me._ModelName
End Get
Set(value As String)
Me._ModelName = value
End Set
End Property
Private _ModelYears As EntitySet(Of dbModelYears) = New EntitySet(Of dbModelYears)
<Association(Storage:="_ModelYears", DeleteRule:="CASCADE", OtherKey:="ModelID")> _
Public Property ModelYears As EntitySet(Of dbModelYears)
Get
Return _ModelYears
End Get
Set(value As EntitySet(Of dbModelYears))
_ModelYears.Assign(value)
End Set
End Property
End Class
Joined table:
<Table(Name:="ModelYears")> Public Class dbModelYears
Implements INotifyPropertyChanged
Private _changed As Boolean
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Public Property Changed() As Boolean
Get
Return _changed
End Get
Set(ByVal value As Boolean)
If _changed <> value Then
_changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Private _ModelYearID As Integer
<Column(Storage:="_ModelYearID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ModelYearID")> _
Public Property ModelYearID() As Integer
Get
Return Me._ModelYearID
End Get
Set(value As Integer)
Me._ModelYearID = value
End Set
End Property
Private _ModelID As Integer
<Column(Storage:="_ModelID", DbType:="int", Name:="ModelID")> _
Public Property ModelID() As Integer
Get
Return Me._ModelID
End Get
Set(value As Integer)
Me._ModelID = value
End Set
End Property
Private _ModelYear As String
<Column(Storage:="_ModelYear", DbType:="Varchar(50)", Name:="ModelYear")> _
Public Property ModelYear() As String
Get
Return Me._ModelYear
End Get
Set(value As String)
Me._ModelYear = value
End Set
End Property
End Class
Implementing INotifyPropertyChanged or using ObservableCollection wont notify you of changes in the database. You are going to have to execute the query every time you want to retrieve new data from the database.
Alternatively you could possibly use SqlDependency to set up a query notification dependency between your application and an instance of SQL Server.
EDIT:
From comments.
To hook up the PropertyChanged event of the items in the collection.
For Each item As var In itemsCollection
Dim notifyItem = TryCast(item, INotifyPropertyChanged)
If item IsNot Nothing Then
AddHandler notifyItem.PropertyChanged, AddressOf ItemChanged
End If
Next
Public Sub ItemChanged(sender As Object, e As PropertyChangedEventArgs)
'Handle event
End Sub
I read some articles and blogs on Implementation if IDisposable and GC working set. However, I could not understand the core areas of differentiation like:
Following is code of my test class:
Imports System.ComponentModel
Namespace Classes
Public Class BaseClass
Implements INotifyPropertyChanged
Implements IDisposable
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Friend Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Public Class GenreClass
Inherits BaseClass
#Region "Private Variables"
Private _GenreValue As String
Private _IconValue As String
Private _IsSelectedValue As Boolean
Private _IsExpandedValue As Boolean
#End Region
#Region "Property Variables"
Property Genre As String
Get
Return _GenreValue
End Get
Set(Value As String)
If Not _GenreValue = Value Then
_GenreValue = Value
NotifyPropertyChanged("Genre")
End If
End Set
End Property
Property Icon As String
Get
Return _IconValue
End Get
Set(Value As String)
If Not _IconValue = Value Then
_IconValue = Value
NotifyPropertyChanged("Icon")
End If
End Set
End Property
Property IsSelected As Boolean
Get
Return _IsSelectedValue
End Get
Set(Value As Boolean)
If Not _IsSelectedValue = Value Then
_IsSelectedValue = Value
NotifyPropertyChanged("IsSelected")
End If
End Set
End Property
Property IsExpanded As Boolean
Get
Return _IsExpandedValue
End Get
Set(Value As Boolean)
If Not _IsExpandedValue = Value Then
_IsExpandedValue = Value
NotifyPropertyChanged("IsExpanded")
End If
End Set
End Property
#End Region
Protected Overrides Sub Dispose(disposing As Boolean)
Genre = Nothing
MyBase.Dispose(disposing)
End Sub
Public Overrides Function ToString() As String
Return Genre
End Function
End Class
End Namespace
My Test scenarios are as follows:
Test1:
Dim list1 As New List(Of HODLib.Classes.GenreClass)
For i = 0 To 4
Using z As New HODLib.Classes.GenreClass
With z
.Genre = "asdasd"
.Icon = "asdasdasdasdasd"
.IsExpanded = True
.IsSelected = True
End With
list1.Add(z)
End Using
Next
For Each z In list1
MessageBox.Show(z.ToString)
Next
result of test1 is that GC is called immediately and I loose access to resources, I get null message.
Test2:
Dim list1 As New List(Of HODLib.Classes.GenreClass)
For i = 0 To 4
Dim z As New HODLib.Classes.GenreClass
With z
.Genre = "asdasd"
.Icon = "asdasdasdasdasd"
.IsExpanded = True
.IsSelected = True
End With
list1.Add(z)
Next
For Each z In list1
MessageBox.Show(z.ToString)
Next
Result is Dispose is never called, even for z in forloop, I dont understand this, why is z not disposed, is it waiting because the list has reference to its values?
Test3:
Dim list1 As New List(Of HODLib.Classes.GenreClass)
For i = 0 To 4
Dim z As New HODLib.Classes.GenreClass
With z
.Genre = "asdasd"
.Icon = "asdasdasdasdasd"
.IsExpanded = True
.IsSelected = True
End With
list1.Add(z)
z.Dispose()
Next
For Each z In list1
MessageBox.Show(z.ToString)
Next
Result: Test2 vs test3 is calling the dispose manually after adding to the list. Result is that I lost access to resource, I get null message. Why did this happen although I added the object to list before calling the dispose method.
Thank you.
Unfortunately, the Dispose implementation that the Visual Basic IDE auto-generates is wrong in 99.9% of all cases. You should only use it if your class has a Finalize() method or the base class has a protected Dispose(Boolean) method. Which is extremely rare, finalizers are implemented by .NET Framework classes. It is their job to wrap unmanaged resources that should be released early.
It becomes 100% wrong when you find out that you can't write any meaningful code in the Dispose() method. Like this case, your class has no fields of a type that is disposable. Setting a field to Nothing has no effect.
You are adding a reference to the instance z which you create. When that instance is destroyed, the reference is no longer pointing to anything. The Using construct automatically calls Dispose for you. You can make a new copy of the object z by adding a method to the class:
Public Function Clone() As GenreClass
Return DirectCast(Me.MemberwiseClone(), GenreClass)
End Function
and use list1.Add(z.Clone).
See Object.MemberwiseClone Method for more information and if you need to create a deep copy.
I'm creating a program in which I have a publicly defined boolean value
Public boolOverallStatus As Boolean = True
and I need to execute some code whenever the boolean value changes. In previous applications, an actual form item change handled this, but it can be changed by several different subs.
How would I handle this? I'm looking through msdn, but it's rather confusing.
In a nutshell: How to execute code when the event of a boolean value changing occurs.
Make it a property instead.
Private _boolOverallStatus As Boolean = True
Property boolOverallStatus As Boolean
Get
Return _boolOverallStatus
End Get
Set(ByVal value as Boolean)
If value <> _boolOverallStatus Then
_boolOverallStatus = value
'// handle more code changes here.'
End If
End Set
End Property
I use the following pattern which resembles what Microsoft do for most of their Changed events.
Class MyClass
Public Property OverallStatus As Boolean
Get
Return _OverallStatus
End Get
Set (value As Boolean)
If _OverallStatus = value Then Exit Property
_OverallStatus = value
OnOverallStatusChanged(EventArgs.Empty)
End Set
End Property
Private _OverallStatus As Boolean = False
Protected Overridable Sub OnOverallStatusChanged(e As EventArgs)
RaiseEvent OverallStatusChanged(Me, e)
End Sub
Public Event OverallStatusChanged As EventHandler
End Class
In VB, you can handle the event using the WithEvents and Handles keywords:
Class MyParent
Private WithEvents myObject As New MyClass()
Private Sub myobject_OverallStatusChanged(sender As Object, e As EventArgs) Handles myObject.OverallStatusChanged
' TODO: Write handler.
End Sub
End Class
The OnOverallStatusChanged function is useful for inheriting classes to get first shot at responding to the change.
Class MyOtherClass
Inherits MyClass
Protected Overrides Sub OnOverallStatusChanged(e As EventArgs)
' TODO: Do my stuff first.
MyBase.OnOverallStatusChanged(e)
End Sub
End Class
Use public properties instead of public variables. You can then put logic in the Set method of the property to execute whenever the property is.. well set.
http://msdn.microsoft.com/en-us/library/65zdfbdt%28v=VS.100%29.aspx
Private number As Integer = 0
Public Property MyNumber As Integer
' Retrieves number.
Get
Return number
End Get
' Assigns to number.
Set
CallLogicHere()
number = value
End Set
End Property
You could also define an event, which is fired each time the status changes. The advantage is, that changes can be handled by the parts of the application that depend on this status. Otherwise the logic would have to be implemented together with the status.
Other parts of the application can subscribe the event with AddHandler.
Public Class OverallStatusChangedEventArgs
Inherits EventArgs
Public Sub New(newStatus As Boolean)
Me.NewStatus = newStatus
End Sub
Private m_NewStatus As Boolean
Public Property NewStatus() As Boolean
Get
Return m_NewStatus
End Get
Private Set
m_NewStatus = Value
End Set
End Property
End Class
Module modGlobals
Public Event OverallStatusChanged As EventHandler(Of OverallStatusChangedEventArgs)
Private m_boolOverallStatus As Boolean = True
Public Property BoolOverallStatus() As Boolean
Get
Return m_boolOverallStatus
End Get
Set
If Value <> m_boolOverallStatus Then
m_boolOverallStatus = Value
OnOverallStatusChanged(Value)
End If
End Set
End Property
Private Sub OnOverallStatusChanged(newStatus As Boolean)
RaiseEvent OverallStatusChanged(GetType(modGlobals), New OverallStatusChangedEventArgs(newStatus))
End Sub
End Module