I'm searching a way to serialize a structure that contains different kind of object such as Strings, Integer and Collections.
I have this data structure:
Dim database as New mainStruct
<Serializable()> Structure mainStruct
Public name As String
Public address As String
Public Shared bookings As IList(Of booking) = New List(Of booking)
End Structure
<Serializable()> Structure booking
Public id As Integer
Public category As String
Public description As String
End Structure
running the serializer:
Dim fs As FileStream = New FileStream("x.bin", FileMode.OpenOrCreate)
Dim serial As New XmlSerializer(GetType(mainStruct))
serial.Serialize(fs, database)
fs.Close()
the output only contains all non-collection variables such as:
<?xml version="1.0"?>
<mainStruct xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>foo</name>
<address>bar</address>
</mainStruct>
How i can serialize bookings Collection, without creating separate files using GetType(List(Of booking))?
Thanks!
Shared members are not serialized because serialization is all about saving a class/structure instance, and shared members are not part of an instance.
Add an instance property to your structure and you should be good to go:
Public Property bookingList As IList(Of booking)
Get
Return mainStruct.bookings
End Get
Set(value As IList(Of booking)
mainStruct.bookings = value
End Set
End Property
If you want the tag to be called <bookings> you can just apply an XmlArray attribute to the property:
<XmlArray("bookings")> _
Public Property bookingList As IList(Of booking)
...same code as above...
End Property
Related
AutoMapper with VB.NET
I have the following classes below. OrderA With List (Of OrderALineItem) and OrderBList With List (Of OrderB). I want to copy data from OrderA to OrderBList. Which copies ItemName, ItemQty, Price from List (Of OrderALineItem) to List (Of OrderB) and OrderID, CustomerName from OrderA itself. I have found almost all codes in C# and am not able to convert it to vb.net code.
Public Class OrderA
Public Property OrderID As String
Public Property CustomerName As String
Public Property OrderLineItem As List(Of OrderALineItem)
End Class
Public Class OrderALineItem
Public Property ItemName As String
Public Property ItemQty As Integer
Public Property Price As Decimal
End Class
Public Class OrderBList
Public Property OrderBLineItem As List(Of OrderB)
End Class
Public Class OrderB
Public Property OrderID As String
Public Property CustomerName As String
Public Property ItemName As String
Public Property ItemQty As Integer
Public Property Price As Decimal
End Class
My VB.NET code until now is:
Dim mapperConfiguration = New MapperConfiguration(Sub(config)
config.CreateMap(Of OrderALineItem, OrderBList)()
End Sub)
Dim mapper = mapperConfiguration.CreateMapper()
Dim objOrderB = mapper.Map(Of OrderBList)(objOrder.OrderLineItem)
The above code creates and object from copies the data from objOrder.OrderLineItem to OrderBList. That's it.
Can anybody help me out on this in VB.NET.
Note: Am totally new in AutoMapper
Version: AutoMapper 6.2.2.0
Done myself, I hope the code below will be helpful to somebody.
Dim mapperConfiguration = New MapperConfiguration(Sub(config)
config.AddProfile(New CustomProfile_1)
End Sub)
Dim objMapper = mapperConfiguration.CreateMapper()
Dim objOrderB As List(Of Dest_OrderB) = objMapper.Map(Of Src_OrderA, List(Of Dest_OrderB))(objOrderA)
Public Class CustomProfile_1
Inherits Profile
Sub New()
CreateMap(Of Src_OrderALineItem, Dest_OrderB)()
CreateMap(Of Src_OrderA, List(Of Dest_OrderB))() _
.ConstructProjectionUsing(
Function(Src1) Src1.List_Src_OrderALineItem.Select(Function(Src2) New Dest_OrderB _
With {.CustomerName = Src1.CustomerName,
.OrderID = Src1.OrderID,
.ItemName = Src2.ItemName,
.ItemQty = Src2.ItemQty,
.Price = Src2.Price}
).ToList())
End Sub
End Class
I'm working on a huge project here and I'll try to simplify the question as much as I can.
It is Basically a DLL which saves the rights of each user to a Database and returns it to the application, this whole thing using Entity Framework.
Here the Classes, I'll not insert all of them, but just two that create a n:m Relashionship:
Public Class Group
Inherits Object
<Key>
Public Property GroupID As Long
<Required>
Public Property GroupName As String
Public Overridable Property Rights As ICollection(Of Rights) = New HashSet(Of Rights)
And here the other one:
Public Class Rights
<Key>
Public Property ID As Long
<Required>
Public Property Number As Integer
<Required>
Public Property Name As String
Public Property Description As String
Public Overridable Property Groups As ICollection(Of Groups) = New HashSet(Of Groups)
So far so good. This whole data comes from *.csv Files, which I read in as DataTable, return it to another DLL which takes the DataTable, makes objects from each Class and returns the Objects as an ICollection, this works fine as well.
Here the two functions from this classes, so the two functions that take the data From the DataTable, makes objects out of it and return it as ICollection:
Public Function ReturnAllGroups(ByVal dt As DataTable) As ICollection(Of Group) Implements IInfoServiceUtil.ReturnAllGroups
If dt Is Nothing Then
Throw New ArgumentNullException("DataTable can't be nothing", "dt")
End If
If Not dt.Columns.Contains("Profile") Then
Throw New ArgumentException("Couldn't find Column Profile")
End If
Dim profilNames = From row In dt.AsEnumerable()
Select row.Field(Of String)("Profile") Distinct
Dim coll As ICollection(Of Group) = New List(Of Group)
For Each name In profilNames
If name <> Nothing Then
Dim group As Group= New Group()
groupg.GroupName = name
coll.Add(group)
End If
Next
Return coll
End Function
And here the other onde:
Public Function ReturnAllRights(ByVal dt As DataTable) As ICollection(Of Rights) Implements IInfoServiceUtil.ReturnAllRights
If dt Is Nothing Then
Throw New ArgumentNullException("DataTable can't be nothing!", "dt")
End If
If Not dt.Columns.Contains("RightName") Then
Throw New ArgumentException("Couldn't find column RightName!")
End If
If Not dt.Columns.Contains("RightNumber") Then
Throw New ArgumentException("Couldn't find column RightNumber!")
End If
Dim query = From dr As DataRow In dt.DefaultView.ToTable(True, "RightName", "RightNumber")
Dim coll As ICollection(Of Rights) = New List(Of Rights)
For Each row In query
Dim right As Rights = New Rights()
If IsNumeric(row.Item("RightNumber")) Then
With right
.Name = row.Item("RightName")
.Number= row.Item("RightNumber")
coll.Add(right)
End With
End If
Next
Return coll
End Function
This works fine as well. And in this part I'm stucked, coz I'm not sure how I can make the association Table from the Group and Rights Tables.
It would be a Function like this:
Public Function CreateAssociation(group As ICollection(Of Groups), right As ICollection(Of Rights), dt As DataTable) As ICollection(Of Group)
'TODO
Return coll
End Function
Sorry if it's a long question, but any help would be much appreciated. I have more Tables as well, but as soon as I know how to do one, the others will work just fine.
Thanks a lot!
I'm trying to teach myself reflection and have been googling but I can't wrap my head around it entirely. I created a class called DataClass which contains a method called GetClassFromDB as you can see below, which will be inherited from multiple classes.
What I am attempting to do is have my dataclass read the TableName property that is defined within objResults. Once I pull in the tablename from objResults I would query the SQL database for a dataset. Once I have the dataset I would create a new object of the same TYPE inheriting this class (Which will be different types) and populate it from the dataset. Once I have the newly populated class I will return it for use.
I believe I have gotten most of the way there properly (Please correct me if there is a better way), but my real question is this. How can I create a new class of the type thats deriving that class from that string name that I getting in my code, or the type. I would want to have all the accessible properties from objResults available.
Namespace MyApp
Public Class DataClass
Private _TableName As String
Private _Name As String
Overridable ReadOnly Property TableName As String
Get
Return _TableName
End Get
End Property
Public Overloads Function GetClassFromDB() As Object
Try
Dim BaseObject As New Object
'Get the object name
Dim objName As String = MyBase.GetType().Name
'Gets the type thats calling this method
Dim objDerived As Type = MyBase.GetType()
'Get the property info to request the tablename from the derived class
Dim TableName As PropertyInfo = objDerived.GetProperty("TableName")
Dim TableNameString As String = TableName.GetValue(Me, Nothing).ToString
'Once I get the table name from objResults I can perform the SQL
Dim QueryResults as DataSet = SQLiteCLass.Query("Select * FROM TableNameString")
'Once I get data from the SQL I want to create a new object of the type deriving this method.
'In this example is objResults
Dim NewObject as objDerived
'Now I can fill my new object with the results and return it as an object
'THIS IS MY QUESTION - How can I create a new object of the TYPE that I receive from Reflection
Return False
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
and this is a sample class that would inherit my dataclass.
Public Class objResults
Inherits MyApp.DataClass
Private _GameID As Guid
Public Property GameID As Guid
Get
Return _GameID
End Get
Set(ByVal value As Guid)
_GameID = value
End Set
End Property
Public Overrides ReadOnly Property TableName As String
Get
Return "This is my tablename"
End Get
End Property
End Class
and this is how I would use this in code.
Dim objResult as New objResults
Dim TodaysResult as objResultsCollection
TodaysResult = objResult.GetClassFromDB()
I have a set of classes, whose properties have data annotations on them. Some of these class properties are of primitive types (and by primitive, I also mean types such as string, double, datetime etc), while others are properties of a custom type.
I would like to be able to iterate through the properties of a class and the properties of the nested objects and pull out the attributes of each property. I’ve played around with reflection and my code works fine, if the class under consideration has only one property of a custom type.
However when a class has multiple properties of a custom type and each of those properties have other custom types, I am completely lost on how I’d keep track of the objects/properties that have already been visited.
This is where I have got so far. I have seen a lot of examples on the forum, but they all have a simple nested class, where there is a maximum of one custom type per class.
Below is a sample of what I am trying to get done:
Public Class Claim
<Required()>
<StringLength(5)>
Public Property ClaimNumber As String
<Required()>
Public Property Patient As Patient
<Required()>
Public Property Invoice As Invoice
End Class
Public Class Patient
<Required()>
<StringLength(5)>
Public Property MedicareNumber As String
<Required()>
Public Property Name As String
<Required()>
Public Property Address As Address
End Class
Public Class Address
Public Property Suburb As String
Public Property City As String
End Class
Public Class Invoice
<Required()>
Public Property InvoiceNumber As String
<Required()>
Public Property Procedure As String
End Class
Public Shared Function Validate(ByVal ObjectToValidate As Object) As List(Of String)
Dim ErrorList As New List(Of String)
If ObjectToValidate IsNot Nothing Then
Dim Properties() As PropertyInfo = ObjectToValidate.GetType().GetProperties()
For Each ClassProperty As PropertyInfo In Properties
Select Case ClassProperty.PropertyType.FullName.Split(".")(0)
Case "System"
Dim attributes() As ValidationAttribute = ClassProperty.GetCustomAttributes(GetType(ValidationAttribute), False)
For Each Attribute As ValidationAttribute In attributes
If Not Attribute.IsValid(ClassProperty.GetValue(ObjectToValidate, Nothing)) Then
ErrorList.Add("Attribute Error Message")
End If
Next
Case Else
Validate(ClassProperty.GetValue(ObjectToValidate, Nothing))
**** ‘At this point I need a mechanism to keep track of the parent of ClassProperty and also mark ClassProperty as visited, so that I am able to iterate through the other properties of the parent (ObjectToValidate), without revisiting ClassProperty again.**
End Select
Next
End If
Return Nothing
End Function
The most straightforward (and probably easiest) way to approach this is to keep a Dictionary of class property attributes keyed by class name.
If I were approaching this, I would probably create a class to hold the property attributes:
Public Class PropertyAttribute
Public PropertyName As String
Public PropertyTypeName As String
Public Required As Boolean
Public StringLength As Integer
End Class
Then create a class to hold information about each class' properties:
Public Class ClassAttributes
Public ClassName As String
' You could also use a dictionary here to key properties by name
Public PropertyAttributes As New List(Of PropertyAttribute)
End Class
Finally, create a dictionary of ClassAttributes to keep track of which custom classes you have already processed:
Public ProcessedClasses As New Dictonary(Of String, ClassAttributes)
The key for the dictionary is the classname.
When you are processing the attributes through reflection, if the property type is custom, check the dictionary for the existence of the class. If it is there, you don't have to process it.
If it is not there, add a new instance to the dictionary immediately (so that nested objects of the same type are safely handled) and then process the attributes of the class.
I have successfully deserialized my xml file using XmlSerializer in .Net but trying to serialize that data back to an xml file is becoming frustrating. When I try to serialize my classes I only get the root tag of the xml with no child elements. How can I serialize all my objects to get the correct xml with data? I have seen somewhere where someone suggested to add the classes to be serialized in a collection and then serialize that collection but I can't wrap my head around that or is there a simpler way of doing it? Any help is appreciated! Here is my code:
Public Shared Function SerializeXml() As Byte()
Dim serializer As New XmlSerializer(GetType(Data))
Dim nameSpaces As XmlSerializerNamespaces = New XmlSerializerNamespaces()
Dim mStream As New MemoryStream()
Dim result As Byte()
Dim target As New Data()
nameSpaces.Add(String.Empty, String.Empty)
serializer.Serialize(mStream, target, nameSpaces)
result = mStream.ToArray()
Return result
And here is a generic sample of the xml with attributes:
<?xml version"1.0">
<RootTag>
<ChildTag Label="Label1" Value="Value1"/>
<ChildTag Label="Label2" Value="Value2"/>
</RootTag>
Edit: Here is my Data class:
Imports System.Xml.Serialization
<XmlRoot("DATA", [Namespace]:="", IsNullable:=False)>
Public Class Data
Inherits Model
<XmlElement("CONFIGURATION")>
Public Property Configuration() As DataConfiguration
Get
Return Me._Configuration
End Get
Set(value As DataConfiguration)
Me._Configuration = value
End Set
End Property
Private _Configuration As DataConfiguration
<XmlElement("FIELD")>
Public Property Field() As Field
Get
Return Me._Field
End Get
Set(value As Field)
Me._Field = value
End Set
End Property
Private _Field As Field
<XmlElement("LIST")>
Public Property ListRoot() As List(Of ListRoot)
Get
Return Me._ListRoot
End Get
Set(value As List(Of ListRoot))
Me._ListRoot = value
End Set
End Property
Private _ListRoot As List(Of ListRoot)
End Class
This is your issue here, <XmlRoot("DATA", [Namespace]:="", IsNullable:=False)>. The IsNullable property, when set to false, will omit the XML for items if they are equal to nothing. If you set the IsNullable to True, then it will emit a tag like this <ListRoot xsi:nil = "true" />. In your code example, since you just created a new Data class like this Dim target As New Data(), all of the members are Nothing by default. Since you've set the IsNullable = False, you should only see that root tag, and that would be a valid serialization of the data.