Update columns in one LINQ object with another LINQ object - vb.net

I have two LINQ objects which have exactly the same columns and I would like to be able to update one with the fields from the other. I first create a new object from some data in a file, then I query the database for an existing item with the same ID. What I would like to be able to do is update the existing objects details with the newly created objects details.
So far the way I have been doing it is to list all the columns and update them manually but as you can see this can cause maintenance headaches.
With OldCaller
.ADDRESS = NewCaller.ADDRESS
.COMPANY = NewCaller.COMPANY
.CONTACT_HOURS = NewCaller.CONTACT_HOURS
.CONTACT_NAME = NewCaller.CONTACT_NAME
.CUSTOMER_ID = NewCaller.CUSTOMER_ID
.EMAIL_ADDRESS = NewCaller.EMAIL_ADDRESS
.FAX_NUMBER = NewCaller.FAX_NUMBER
.FAX_TYPE = NewCaller.FAX_TYPE
.MOBILE = NewCaller.MOBILE
.POSTCODE = NewCaller.POSTCODE
.PUBLIC_ADDRESS = NewCaller.PUBLIC_ADDRESS
.PUBLIC_TELEPHONE = NewCaller.PUBLIC_TELEPHONE
.STATE = NewCaller.STATE
.SUBURB = NewCaller.SUBURB
.TELEPHONE = NewCaller.TELEPHONE
End With
I would like to be able to find a way to clean this up a bit. Does anyone know of a better way to do what I need.

I do this sort of thing when I create an instance of an object from a template. Basically I have a method that iterates over the public properties of the template, finds the corresponding property in the object being created, and invokes the property setter on the new object, all via reflection.

I haven't tested this yet but this is what I have come up with.
Dim _OldCallerProperties = OldCaller.GetType().GetProperties(Reflection.BindingFlags.Public)
Dim _NewCallerProperties = NewCaller.GetType.GetProperties(Reflection.BindingFlags.Public)
For Each Prop In _OldCallerProperties
Dim _matchingProperty = _NewCallerProperties.Where(Function(p) p.Name = Prop.Name).FirstOrDefault
Dim _newvalue = _matchingProperty.GetValue(_matchingProperty, Nothing)
Prop.SetValue(Prop, _newvalue, Nothing)
Next
Like I said I haven't tested it but I'm sure it should work.

Related

How to use reflection for accessing object from its name as a string

Ive a folder monitoring application where around 25 filewatchers monitoring 25 folders. Each of the filewatchers named fsw1,fsw2 ....
bCreateFileCheck = True
fsw1 = New FileSystemWatcher(My.Settings.UserRootFolder1)
fsw1.IncludeSubdirectories = True
fsw1.EnableRaisingEvents = True
fsw1.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName)
So this is repeating for the 25 folders, but only difference is name changing of fsw1 to fsw2,fsw3 etc. and also My.Settings.UserRootFolder1 to My.Settings.UserRootFolder2,My.Settings.UserRootFolder3 etc.
So how can we achieve this using for loop without writing individual code blocks for every filewatchers. I guess using some reflection techniques it can be achieved.
Don't make your life harder than it needed to be. Use an array (or List(Of T) if you need something flexible):
Dim watchers(24) As FileSystemWatcher
For i As Integer = 0 To watchers.GetUpperBound(0)
Dim path = CStr(My.Settings.Item("UserRootFolder" & (i + 1)))
watchers(i) = New FileSystemWatcher(path)
'Do further initialization...
Next
If the structure is fixed and you cannot really change it, you can set the variables to the objects that you created in the For loop. So change the loop as follows:
'...
Dim watcher = New FileSystemWatcher(...)
Me.GetType().GetField("fsw" & (i + 1)).SetValue(Me, watcher)
This gets the field with the appropriate name and sets its value to the object that you just created (I assume that it is a field based on its naming).

vb.net form linq nullreferenceexception

I'm working on a Sindows Forms application to help keep inventory of some scanners. I'm using Linq2Sql, each table has an id column. On my repair history form. I'm trying to use the serial number from the inventory table so it goes to the database and looks up the sID from the table and it returns the correct value, but when I go to send all the entered data to the history table it gets a null reference exception.
Dim db As New DataClasses1DataContext
Dim rep As Scanner_Repair_History
Dim scan = (From Scanner_Inventory In db.Scanner_Inventories Where scannerid.Text = Scanner_Inventory.SN Select Scanner_Inventory.SID).FirstOrDefault
rep.SID = scan
rep.Date_Broken = datebroke.Value
rep.Description = description.Text
rep.Send_Date = senddate.Text
rep.Recieve_Date = recievedate.Text
rep.Cost = cost.Text
rep.PlantID = plantid.Text
rep.BID = brokenid.Text
rep.RMAnumber = rmanum.Text
db.Scanner_Repair_Histories.InsertOnSubmit(rep)
db.SubmitChanges()
is that me but you didn't instanciate your "rep" variable
You don't have a defined object for placement with a 'new' keyword but I am also curious if it is a system.type.
Update based on Jinx88909
You may be returning an entire POCO Object that may be null and have a null property. You can adjust this most times by doing a null condition if you are using .NET 4.5 and up. '?.' operator.
Dim db As New DataClasses1DataContext
'I need to be a new object and not instantiated as Nothing
Dim rep As New Scanner_Repair_History
'You have the potential for a nothing value here as 'FirstOrDefault' includes a potential Nothing'.
'I would get the entire object and then just a property of it after the fact
Dim scan = (From Scanner_Inventory In db.Scanner_Inventories Where scannerid?.Text = Scanner_Inventory?.SN Select Scanner_Inventory).FirstOrDefault?.Sid
If scan IsNot Nothing Then
rep.SID = scan 'Could you maybe want scan.Id or something similar?
rep.Date_Broken = datebroke.Value
rep.Description = description.Text
rep.Send_Date = senddate.Text
rep.Recieve_Date = recievedate.Text
rep.Cost = cost.Text
rep.PlantID = plantid.Text
rep.BID = brokenid.Text
rep.RMAnumber = rmanum.Text
db.Scanner_Repair_Histories.InsertOnSubmit(rep)
db.SubmitChanges()
Else
Console.WriteLine("I got nothing for you with the inputs you put in!")
End If

Tracking Controls via an Array

so I have an array that holds picture boxes. Can someone help me in coding a much, much more efficient way in assigning each index? I just can't figure it out.
ArrayBullets(0) = picBullet0
ArrayBullets(1) = picBullet1
ArrayBullets(2) = picBullet2
ArrayBullets(3) = picBullet3
ArrayBullets(4) = picBullet4
ArrayBullets(5) = picBullet5
ArrayBullets(6) = picBullet6
ArrayBullets(7) = picBullet7
ArrayBullets(8) = picBullet8
ArrayBullets(9) = picBullet9
ArrayBullets(10) = picBullet10
ArrayBullets(11) = picBullet11
ArrayBullets(12) = picBullet12
ArrayBullets(13) = picBullet13
ArrayBullets(14) = picBullet14
ArrayBullets(15) = picBullet15
ArrayBullets(16) = picBullet16
ArrayBullets(17) = picBullet17
ArrayBullets(18) = picBullet18
ArrayBullets(19) = picBullet19
ArrayBullets(20) = picBullet20
ArrayBullets(21) = picBullet21
ArrayBullets(22) = picBullet22
ArrayBullets(23) = picBullet23
ArrayBullets(24) = picBullet24
ArrayBullets(25) = picBullet25
ArrayBullets(26) = picBullet26
ArrayBullets(27) = picBullet27
ArrayBullets(28) = picBullet28
ArrayBullets(29) = picBullet29
It would be much appreciated.
There is generally no reason at all to do this. They can always be found in the Controls Collection (you will not find them among Components). Though it looks ordered, your list is actually a bit arbitrary; they will always be in the Controls Collection in ZOrder which starts as the order added to the Designer and may or may not matter.
If you need a way to track them, rather than storing a reference, you can use a List(Of String) to store their names to use to reference them in the controls collection. If a control reference is somehow important, then a List(Of PictureBox) could be used instead.
Private myPicBoxes As New List(of String)
Method One - add names in Form Load:
For n As Integer = 0 To 29
myPicBoxes.Add(String.Format("picBullet{0}", n.ToString))
Next n
Method Two - get names from controls in Form Load
For Each pb As PictureBox In Me.Controls.OfType(Of PictureBox)
mypicBoxes.Add(pb.Name)
Next
To do something with a particular PB:
Me.Controls( myPicBoxes( mypicBoxes(theIndex) ) ).Image = FileName
Clear all images:
For Each pbName As String in myPicBoxes
Me.Controls(pbName).Image = Nothing
Next
' or
For n As Integer = 0 To myPicBoxes.Count - 1
Me.Controls(myPicBoxes(n)).Image = Nothing
Next n
If they are dynamic (you remove or add PictureBoxes at runtime) add/remove to your List as well:
Dim pb As New PictureBox
... set props
pb.Name = whatever you want
myPicBoxes.Add(pb.Name)
Me.Controls.Add(pb)
Removing:
Me.Controls.Remove( mypicBoxes(n))
mypicBoxes.RemoveAt(n) ' also remove the name from your tracker
If you're using the form designer designer to create your UI, populating the array manually really is the simplest and probably the best option.
You could iterate over Controls to find all the PictureBoxes and put them into an array; but that won't have a guaranteed sort order because the designer loves to rearrange its code every times you change something.

VB.Net Sort a List using property name

I have a list containing Client objects. I want to sort the list by using it's property name ascending or descending, which I already have in the code in viewstate : ViewState("PropertyName") and ViewState("Order")
Dim objList As List(Of Client) = Session("ClientList")
objList.Sort(ViewState("PropertyName") + " " + ViewState("Order"))
datarepeater.datasource = objList
How can I achieve this ?
Normally, if you knew the property with which you wanted to sort, you would be able to just do something like this:
clients.Sort(Function(x, y) x.Name.CompareTo(y.Name))
In the above example, I am, of course sorting on the Name property (I don't know what properties the Client class has, I'm just using it as an example.
However, since you don't know which property you are going to use until run-time, you'll need to do something more complicated. If you really want to use the actual property names of the class, you could use Reflection to retrieve the value of the property dynamically, for instance:
clients.Sort(Function(x, y)
Dim xProperty As PropertyInfo = x.GetType().GetProperty(ViewState("PropertyName").ToString)
Dim yProperty As PropertyInfo = y.GetType().GetProperty(ViewState("PropertyName").ToString)
Dim xValue As Object = xProperty.GetValue(x)
Dim yValue As Object = yProperty.GetValue(y)
Return xValue.ToString().CompareTo(yValue.ToString())
End Function)
To reverse the sort order, just multiply the return value by -1, or switch which object you are comparing to what. For instance:
If ViewState("Order") = "Ascending" Then
Return xValue.ToString().CompareTo(yValue.ToString())
Else
Return yValue.ToString().CompareTo(xValue.ToString())
End If
You can also use Linq (using the same general method proposed by Steven Doggart):
sorted = lst.OrderBy(Function(x) x.GetType().GetProperty(_strColumnName01).GetValue(x)). _
ThenBy(Function(x) x.GetType().GetProperty(_strColumnName02).GetValue(x)).ToList()
In my particular example, I needed to sort by two columns, but for just a single column:
sorted = lst.OrderBy(Function(x) x.GetType().GetProperty(_strColumnName01).GetValue(x)).ToList()

Passing lists from WCF to WCF in VB

I'm trying to populate one list from another. I would think this code should work, but at the end of the day I get a list of identical items.
Public Sub WriteDatFile(ByRef lstReasons As System.Collections.Generic.List(Of LetterReason))
Dim tmplstReason As New TCPService.LetterReason
Dim tmplstReasons As New System.Collections.Generic.List(Of TCPService.LetterReason)
'Load the letter reasons
For Each LetterReason In lstReasons
tmplstReason._reason = LetterReason.Reason
tmplstReasons.Add(tmplstReason)
Next
RetVal = .......
End Sub
Now, when I set a breakpoint and check from the calling WCF I get this:
lstReason(0).Reason = One
lstReason(1).Reason = Two
lstReason(2).Reason = Three
But, when I set a breakpoint (after the load) in this subroutine I get the following output:
tmplstReason(0)._reason = Three
tmplstReason(0)._reason = Three
tmplstReason(0)._reason = Three
What's going on??? Any ideas?
Thanks,
Jason
You need to create a new instance of LetterReason inside the loop and add the new instance to the list. Try this
For Each LetterReason In lstReasons
Dim tmplstReason As New TCPService.LetterReason
tmplstReason._reason = LetterReason.Reason
tmplstReasons.Add(tmplstReason)
Next
tmplstReason._reason = LetterReason.Reason
tmplstReasons.Add(tmplstReason)
Look carefully. You're not actually changing tmplstReason, you're changing the ._reason property of it. You then add tmplstReason to the list 3 times.
The result is that you actually add the same thing to the list each time, and change that one object's ._reason variable each time. Since they're all the same, they all have the same value. :)