Assigning Private Property values - petapoco

I'm testing out PetaPoco to determine if it meets our needs. I was under the impression that it would delve into my class and see the private properties that I've marked up as valid columns. Unfortunately, it's not behaving as expected. Can you please take a look and let me know if I'm doing something wrong.
My test class:
Imports PetaPoco
<PetaPoco.TableName("PaulTest")>
<PetaPoco.PrimaryKey("ID")>
Public Class PaulTest
<PetaPoco.Column("ID")>
Private Property pvtID As Integer
Private pvtName As String
Private Sub New()
End Sub
Public Sub New(name As String)
If String.IsNullOrEmpty(name) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = name
End Sub
<PetaPoco.Ignore>
Public ReadOnly Property ID As Integer
Get
Return pvtID
End Get
End Property
<PetaPoco.Column("Name")>
Public Property Name As String
Get
Return pvtName
End Get
Set(value As String)
If String.IsNullOrEmpty(value) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = value
End Set
End Property
End Class
The call to the DB (_db is a PetaPoco database object)
Return (_db.Fetch(Of Peta.Domain.PaulTest)(";EXEC selAllPaulTest")).OrderBy(Function(PaulTest) (PaulTest.ID)).ToList()
What's in the database
ID Name
107 Paul
What's being returned:
PaulTest.ID = 0
PaulTest.pvtID = 0
PaulTest.Name = "Paul"
PaulTest.pvtName = "Paul"

<PetaPoco.Ignore> attribute instructs PetaPoco to ignore the column during mapping. As such, the property Id will always be returning the default value of 0.
If you want to prevent the Id property from being modified, comment our or delete the attribute and add a private setter to the Id property as in the following code snippet.
' <PetaPoco.Ignore>
Public Property Id As Integer
Get
Return pvtID
End Get
Private Set(value As Integer)
pvtID = value
End Set
End Property

Related

Comparing list of class by string length and text comparison

I have a List(Of Abbreviation).
The class "Abbreviation" contains the string members "Input", "Output" and "CaseSensitive".
The class is stated below.
I would like to sort this list so that the class with the "Input"
"ZZZ"
comes before
"zz"
The comparison should thus first compare by string length, then by alphetical order, and then by CaseSensitive.
How could I sort the list this way?
Public Class Abbreviation
Implements IComparable
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Property Input() As String
Get
Return _sIn
End Get
Set(value As String)
_sIn = value
End Set
End Property
Public Property Output() As String
Get
Return _sOut
End Get
Set(value As String)
_sOut = value
End Set
End Property
Public Property CaseSensitive() As Boolean
Get
Return _bCaseSensitive
End Get
Set(value As Boolean)
_bCaseSensitive = value
End Set
End Property
Public Sub New(ByVal uInput As String, ByVal uOutput As String, ByVal uCaseSensitive As Boolean)
_sIn = uInput
_sOut = uOutput
_bCaseSensitive = uCaseSensitive
End Sub
End Class
First, you can simplify your code by using automatic properties. The compiler writes the get, set, and backer fields (the private fields). This is the preferred way in recent versions of Visual Studio if there is no extra code in the getter, setter.
Another small detail with your Sub New. It violates encapsulation to set the private fields directly. Always go through the Public Properties. There could be code in the setter that needs to run before storing the data in the private fields. Classes like to keep their data close to the vest in their private fields.
Example of Auto Implemented Properties
Public Property Input As String
Public Property Output As String
Public Property CaseSensitive As Boolean
The sort can be done in one line of code using a Linq query.
Dim orderedList = From abrev In lstAbreviations Order By abrev.Input.Lenght Descending Select abrev
To check the output...
For Each abrev As Player In orderedList
Debug.Print(abrev.Input)
Next
I think I got it, except the case sensitivity. CaseSensitive should come before CaseSensitive = False.
Public Class Abbreviation
Implements IComparable(Of Abbreviation)
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Function CompareTo(uOther As Abbreviation) As Integer _
Implements IComparable(Of Abbreviation).CompareTo
If uOther.Input.Length > Me.Input.Length Then
Return 1
ElseIf uOther.Input.Length < Me.Input.Length Then
Return -1
Else
If uOther.Input > Me.Input Then
Return 1
Else
Return -1
End If
End If
End Function

VB .Net - ShouldSerialize function

I have a problem with ShouldSerialize function.
I defined an usercontrol with a label (named Label1) on it.
Now i put the code below in the usercontrol class :
Imports System.ComponentModel
Public Class UserControl1
Dim _Range As UShort = 100
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = _Range
End Sub
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 200
End Function
Public Sub ResetTBValueRange()
_Range = 200
Label1.Text = _Range
End Sub
Public Property TBValueRange As UShort
Get
Return _Range
End Get
Set(ByVal Steps As UShort)
_Range = Steps
Label1.Text = _Range
End Set
End Property
End Class
Now in a new form include the usercontrol.
In the properties grid of the usercontrol u can find the property TBValueRange.
If you right click in the property name you can Reinit the property.
After reinit u can see value 200 in the property.
Now, regenerate the project will reset the property to the initial value (id 100).
Why the value 200 didn't stay?
If i replace the line Return _Range <> 200 in the function ShouldSerializeTBValueRange() by
Return Not _Range.Equals(200)
it will work.
i don't understand.
Anyone could explain this?
The methods are working as coded. The thing which seems to not work as expected is the Not _Range.Equals(200) portion.
You initialize _Range to 100: Dim _Range As UShort = 100
Then, your ShouldSerializeTBValueRange method tells VS to only save the range value when it is not 200: Return _Range <> 200
So, when you reset it to 200 in the IDE, it wont save a value of 200, and the initial value of 100 displays.
The code uses one value for the default, 100 but use a different value for ShouldSerialize test. You should either change it to use a default of 200:
Dim _Range As UShort = 200
Or change the ShouldSerialize test to use 100:
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 100
End Function
Treating the default value as the default, and using only one value for the default everything works as expected using just ShouldSerializexxx and Resetxxx with no need for anything else.
' THIS is the default value -
' ie the value that need not be saved because the
' control automatically starts with that value
Dim _Range As UShort = 200US
' Controls:
' - displays the prop value in Bold in the property window
' when the value is NOT the default
' - saves the value when it is NOT the default
' - enables/disables the RESET function
Public Function ShouldSerializeTBValueRange() As Boolean
Return (_Range <> 200US)
End Function
Using one value for the actual default (100) and then returning T/F based on a different value (200) results in
100 being saved when it need not be
200 not being saved when it should be
the Reset menu item and Bold value being in the incorrect state
The oddity is that Not _Range.Equals(200) seems to fail. It returns False after a reset (to 200) which causes the value to be saved when it really should not. There are 2 overloads for this:
UInt16.Equals(obj As Object) As Boolean
UInt16.Equals(v As UShort) As Boolean
If you pass anything other than an actual UInt16/UShort, the value will be boxed as Object. So, Not _Range.Equals(200) is using the first because 200 is Int32. The ILCode for that version is:
public override bool Equals(object obj)
{
return obj is ushort && this == (ushort)obj;
}
The test will fail the first test because obj contains an Int32. If you pass a UShort, it will work:
UShort.Equals(_Range, 200US)
'or:
_Range.Equals(200US)
All good reasons to understand the different data types, avoid boxing (As Object) and always and forever set Option Strict On.
Thanks you all to have spent time on my question.
I found my answer : when ShouldSerialize function return false the property value isn't save in the file Form1.designer.vb, so it gets the original value.
For my needed the ShouldSerialize function should always return true.
Public Function ShouldSerializeTBValueRange() As Boolean
Return true
End Function
So the property value will always be saved.
Now, what i'm looking for is how to control the context menu of the property grid.
I want the option "Reinit" greyed when the value is good.
Finally, i found something, with the use of PropertyDescriptor.
For whose are interested, we can save properties in the designer.vb file and test the value to reset.
here is my program, based on the article from MSDN - Microsft:
Imports System.ComponentModel
Imports System.Windows.Forms.Design
<Designer(GetType(DemoControlDesigner))>
Public Class UserControl1
Dim _MyProperty1 As String = "Test1"
Dim _MyProperty2 As Integer = 100
Dim _MyProperty3 As UShort = 200
Public Sub New()
InitializeComponent()
End Sub
Public Function CanResetMyProperty1() As Boolean
Return _MyProperty1 <> "Test"
End Function
Public Sub ResetMyProperty1()
_MyProperty1 = "Test"
End Sub
Public Property MyProperty1 As String
Get
Return _MyProperty1
End Get
Set(ByVal Value As String)
_MyProperty1 = Value
End Set
End Property
Public Function CanResetMyProperty2() As Boolean
Return _MyProperty2 <> 150
End Function
Public Sub ResetMyProperty2()
_MyProperty2 = 150
End Sub
Public Property MyProperty2 As Integer
Get
Return _MyProperty2
End Get
Set(ByVal Value As Integer)
_MyProperty2 = Value
End Set
End Property
Public Function CanResetMyProperty3() As Boolean
Return _MyProperty3 <> _MyProperty2
End Function
Public Sub ResetMyProperty3()
_MyProperty3 = _MyProperty2
End Sub
Public Property MyProperty3 As UShort
Get
Return _MyProperty3
End Get
Set(ByVal Value As UShort)
_MyProperty3 = Value
End Set
End Property
End Class
Friend NotInheritable Class SerializePropertyDescriptor
Inherits PropertyDescriptor
Private _pd As PropertyDescriptor = Nothing
Public Sub New(ByVal pd As PropertyDescriptor)
MyBase.New(pd)
_pd = pd
End Sub
Public Overrides ReadOnly Property Attributes() As AttributeCollection
Get
Return Me._pd.Attributes
End Get
End Property
Protected Overrides Sub FillAttributes(ByVal attributeList As IList)
MyBase.FillAttributes(attributeList)
End Sub
Public Overrides ReadOnly Property ComponentType() As Type
Get
Return Me._pd.ComponentType
End Get
End Property
Public Overrides ReadOnly Property Converter() As TypeConverter
Get
Return Me._pd.Converter
End Get
End Property
Public Overrides Function GetEditor(ByVal editorBaseType As Type) As Object
Return Me._pd.GetEditor(editorBaseType)
End Function
Public Overrides ReadOnly Property IsReadOnly() As Boolean
Get
Return Me._pd.IsReadOnly
End Get
End Property
Public Overrides ReadOnly Property PropertyType() As Type
Get
Return Me._pd.PropertyType
End Get
End Property
Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
Try
Return CallByName(component, "CanReset" & _pd.Name, CallType.Get, Nothing)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return False
End Function
Public Overrides Function GetValue(ByVal component As Object) As Object
Return Me._pd.GetValue(component)
End Function
Public Overrides Sub ResetValue(ByVal component As Object)
Me._pd.ResetValue(component)
End Sub
Public Overrides Sub SetValue(ByVal component As Object, ByVal val As Object)
Me._pd.SetValue(component, val)
End Sub
Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
Return True
End Function
End Class
Class DemoControlDesigner
Inherits ControlDesigner
Dim PropertiesToSerialize As String() = {"MyProperty1", "MyProperty2", "MyProperty3"}
Protected Overrides Sub PostFilterProperties(ByVal properties As IDictionary)
Dim original As PropertyDescriptor
For Each PropName As String In PropertiesToSerialize
If properties.Contains(PropName) Then
original = properties(PropName)
properties(PropName) = New SerializePropertyDescriptor(original)
End If
Next
MyBase.PostFilterProperties(properties)
End Sub
End Class
For each property that should be serialized and tested for reset, we should write a sub "CanResetPropertyName" which test the value to reset (see sample).
And the values stay now, even if we regenerate the project.
It's working fine for me, maybe it can be improved.
Regards.

SubmitChanges does not update foreign key to the database

My problem occurs in a Windows Phone 8.1 Silverlight VB application. The CatDataContext defines a table Books with items Title and a foreign key _seriesID, with belongs to a table Series.
<Table()>
Public Class Series
Implements INotifyPropertyChanged, INotifyPropertyChanging
' Define ID: private field, public property, and database column.
Private _seriesID As Integer
<Column(IsPrimaryKey:=True, IsDbGenerated:=True, DbType:="INT NOT NULL Identity", CanBeNull:=False,
AutoSync:=AutoSync.OnInsert)>
Public Property SeriesID() As Integer
Get
Return _seriesID
End Get
Set(ByVal value As Integer)
If _seriesID <> value Then
NotifyPropertyChanging("SeriesID")
_seriesID = value
NotifyPropertyChanged("SeriesID")
End If
End Set
End Property
' Define name: private field, public property, and database column.
Private _Name As String
<Column()>
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
If _Name <> value Then
NotifyPropertyChanging("Name")
_Name = value
NotifyPropertyChanged("Name")
End If
End Set
End Property
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
' Used to notify that a property changed
Private Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "INotifyPropertyChanging Members"
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
' Used to notify that a property is about to change
Private Sub NotifyPropertyChanging(ByVal propertyName As String)
RaiseEvent PropertyChanging(Me, New PropertyChangingEventArgs(propertyName))
End Sub
#End Region
End Class
<Table()>
Public Class Book
Implements INotifyPropertyChanged, INotifyPropertyChanging
' Define ID: private field, public property, and database column.
Private _bookID As Integer
<Column(IsPrimaryKey:=True, IsDbGenerated:=True, DbType:="INT NOT NULL Identity", CanBeNull:=False,
AutoSync:=AutoSync.OnInsert)>
Public Property BookID() As Integer
Get
Return _bookID
End Get
Set(ByVal value As Integer)
If _bookID <> value Then
NotifyPropertyChanging("BookID")
_bookID = value
NotifyPropertyChanged("BookID")
End If
End Set
End Property
' Define title: private field, public property, and database column.
Private _title As String
<Column()>
Public Property Title() As String
Get
Return _title
End Get
Set(ByVal value As String)
If _title <> value Then
NotifyPropertyChanging("Title")
_title = value
NotifyPropertyChanged("Title")
End If
End Set
End Property
' Internal column for the associated series ID value.
<Column()>
Friend _seriesID As Integer
Private _series As EntityRef(Of Series)
<Association(Storage:="_series", ThisKey:="_seriesID", OtherKey:="SeriesID")>
Public Property BookSeries() As Series
Get
Return _series.Entity
End Get
Set(ByVal value As Series)
NotifyPropertyChanging("BookSeries")
_series.Entity = value
If value IsNot Nothing Then
_seriesID = value.SeriesID
End If
NotifyPropertyChanged("BookSeries")
End Set
End Property
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements NotifyPropertyChanged.PropertyChanged
' Used to notify that a property changed
Private Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "INotifyPropertyChanging Members"
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
' Used to notify that a property is about to change
Private Sub NotifyPropertyChanging(ByVal propertyName As String)
RaiseEvent PropertyChanging(Me, New PropertyChangingEventArgs(propertyName))
End Sub
#End Region
Updating of the field Title alone, or the fields Title and _seriesID works fine. However when I only change the _seriesID then no update of the underlying database is done. In this case .GetModifiedMembers shows no modifications.
A reference to a demo project showing this problem is given here: demo project.
Thanks for your attention.
_seriesID (in Book) is just a member variable. You can set it from outside Book because it is Friend, but further nothing happens.
Title, on the other hand, is a property that fires NotifyPropertyChanged. That means that the context is notified that the Book object has been modified if you change Title.
So if you change _seriesID and Title, the Book object is marked as modified and saved, along with the changed value of _seriesID. But if you change _seriesID alone, the object remains 'unchanged'.
I think this is generated code (LINQ-to-SQL? I don't really recognize it) and you shouldn't modify it manually. If you want _seriesID to be changed, you have to set BookSeries.

VB.Net check for duplicate items in a collection base

I have a class that inherits from CollectionBase. I tried to use the contains method to detect whether the Key already exists before inserting a new one. Here is what I have tried.
<Serializable()> Public Class validationList
Inherits CollectionBase
Public Function Add(ByVal Item As validationItem) As Integer
Return Me.List.Add(Item)
End Function
Default Public ReadOnly Property Item(ByVal index As Integer) As validationItem
Get
Return CType(List.Item(index), validationItem)
End Get
End Property
Public Sub Remove(ByVal index As Integer)
Me.List.RemoveAt(index)
End Sub
Protected Overrides Sub OnInsert(ByVal index As Integer, ByVal value As Object)
If Me.List.Contains(value) Then MsgBox("Already exist")
MyBase.OnInsert(index, value)
End Sub
Public Function IndexOf(ByVal key As validationItem)
Return List.IndexOf(key)
End Function
Public Sub AddRange(ByVal item() As validationItem)
For counter As Integer = 0 To item.GetLength(0) - 1
List.Add(item(counter))
Next
End Sub
End Class
<Serializable()> Public Class validationItem
Implements IEquatable(Of validationItem)
Private _key As validationTypes
Private _value As String
Public Sub New()
' Empty constructor is needed for serialization
End Sub
Public Sub New(ByVal k As validationTypes, ByVal v As String)
_key = k
_value = v
End Sub
Public Enum validationTypes
Madatory = 0
[Integer] = 1
Numeric = 2
[Decimal] = 3
MaxValue = 4
MinValue = 5
MinLength = 6
Email = 7
End Enum
Public Property Value As String
Get
Return _value
End Get
Set(ByVal Value As String)
_value = Value
End Set
End Property
Public Property Key As validationTypes
Get
Return _key
End Get
Set(ByVal value As validationTypes)
_key = value
End Set
End Property
Protected Overloads Function Equals(ByVal eqItem As validationItem) As Boolean Implements IEquatable(Of Testing_Project.validationItem).Equals
If eqItem Is Nothing Then Return False
Return Me._key = eqItem.Key
End Function
Public Overrides Function Equals(ByVal eqItem As Object) As Boolean
If eqItem Is Nothing Then Return False
Dim eqItemObj As validationItem = TryCast(eqItem, validationItem)
If eqItemObj Is Nothing Then Return False
Return Equals(eqItemObj)
End Function
Public Overrides Function GetHashCode() As Integer
Return Me._key.GetHashCode()
End Function
End Class
The validationList will be exposed from a usercontrol as a property, so that items could be added from the designer. When adding items I need to detect whether they already exist. I tried overriding the OnInsert but this sometime return that duplicates exists even when their aren't and doesn't report that duplicate exist when I try to add existing keys.
This indirectly answers the question after dealing with the issue which emerged in comments about Collection(Of T):
Add a reference to System.Collections.ObjectModel if needed, then
Imports System.Collections.ObjectModel
' a ValidationItem collection class
Public Class ValidationItems
Inherits Collection(Of ValidationItem)
Public Shadows Sub Add(NewItem As ValidationItem)
' test for existence
' do not add if it is not unique
Dim dupe As Boolean = False
For n As Int32 = 0 To Items.Count - 1
If Items(n).Key = NewItem.Key Then
dupe = True
Exit For
End If
Next
If dupe = False then
items.Add(newitem)
End if
' I would actually use an IndexOfKey function which might
' be useful elsewhere and only add if the return is -1
If IndexOfKey(NewItem.Key) <> -1 Then
Items.Add(newItem)
End If
End Sub
Some NET collection types implement Add as a function and return the item added. This sounds weird since you pass it the item to add. But returning Nothing if the item cannot be added is a neat semaphore for "I cant/wont do that". I cant recall if the std NET Collection Editor recognizes that or not.
One problem with using Contains is that it will test if item passed as param is the same object as one in the list. They never will be the same object, even if they have the same values. Testing the key in a loop is simpler than calling a method which implements an interface. (That previous answer was totally valid in the context presented, but the context has changed).
Even if you stay with CollectionBase, you want to handle it in the Add. If you try to remove it in OnInsert, VS will have problems deserializing the collection.
Also, your validationitem needs a Name property or the Collection Editor will display "Myassembly+MyType" as the Name (or a ToString override).
Other issues:
I am not sure your IndexOf will work. The list contains ValidationItems (objects), but you check it for _key (string). This will not matter if you change to Collection(Of T) which implements it for you.
The simple ctor is needed by the Collection Editor, not serialization. But the important thing is that it is there.
As for the comment about all Zeroes coming back - that is because your ValidationItem is not yet decorated for designer serialization. Maybe not the Collection Property either, that isnt shown.

Vb.net Property Get and set values without Private variables

Greetins,
I am programmer from some time only, I have certain doubts in fundamentals, could you please clarify on the following:
Case 1:
Public Class BillItems
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Private _BillIdValue As String
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
End If
End Set
End Property
End Class
Case 2:
Public Class BillItems
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Property BillId As String
Get
Return BillId
End Get
Set(ByVal value As String)
If Not BillId = value Then
BillId = value
End If
End Set
End Property
End Case
Does case 1 and case 2 yield same result, I mean is a private value necessarily in there?, can we use property itself to use its own value in its Set and get statements?
Thank you.
I can't imagine that Case 2 is going to run without causing a stack-overflow exception. You are essentially making an infinite loop that is going to constantly call itself.
Case 1 would be the right way to do it.
If you are using .Net 4 you could just do this (without the further Get/Set code):
Property BillId As String
This will generate the private member variable (_BillId) for you.
Edit:
You could try this to raise the event:
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
NotifyPropertyChanged("BillId")
End If
End Set
End Property
In this article on MSDN about Auto-Implemented Properties you can read that a property requires a standard syntax when you
Add code to the Get or Set procedure of a property, such as code to validate incoming values in the Set procedure. For example, you might want to verify that a string that represents a telephone number contains the required number of numerals before setting the property value.
Therefore, because you implement IPropertyChanged interface, you need to add code to the setter.
and write something like this.
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
NotifyPropertyChanged("BillID")
End If
End Set
End Property
The second case is clearly wrong. (Infinite loop as someone else has already said)