How to assign linq anonymous type variable - vb.net

I have a linq query that gives me an System.Collections.Generic.IEnumerable(of <Anonymous Type>). Actually I wanted to create a class to get better access to what I want form that query but I fail aready with declaring a member variable that should hold the query outcome. The query I use in the Sub New() of my class is (explained and c# version here:)
Dim jan1 = New DateTime(DateTime.Today.Year, 1, 1)
Dim startOfFirstWeek = jan1.AddDays(1 - CInt(jan1.DayOfWeek))
Dim weeks = Enumerable.Range(0, 54).[Select](Function(i) New With { _
Key .weekStart = startOfFirstWeek.AddDays(i * 7) _
}).TakeWhile(Function(x) x.weekStart.Year <= jan1.Year).[Select](Function(x) New With { _
x.weekStart, _
Key .weekFinish = x.weekStart.AddDays(4) _
}).SkipWhile(Function(x) x.weekFinish < jan1.AddDays(1)).[Select](Function(x, i) New With { _
x.weekStart, _
x.weekFinish, _
Key .weekNum = i + 1 _
})
My Class should look like:
Public Class WeekInfo
Private _weeks as ?????
end Class
Could anyone tell me what is the usual procedure to accomplish that task and how to put the find a type for my member to access the weeks variable?

VB.Net anonymous types are exposed as type Object so you're variable would be:
Dim weeks As IEnumerable(Of Object)
You will not get intellisense on the anonymous type's fields outside of the function you created them in but you can access them dynamically, i.e.
For Each week In weeks
Console.WriteLine(week.weekStart + " " + week.weekFinish)
Next
If you need to expose the type externally you should define a concrete class or struct instead.

Make your WeekInfo class look like this:
Public Class WeekInfo
Public Property WeekStart As Date
Public Property WeekEnd As Date
Public Property WeekNumber As Int32
End Class
And then load it with you linq query as list of your WeekInfo(s):
Dim jan1 = New DateTime(DateTime.Today.Year, 1, 1)
Dim startOfFirstWeek = jan1.AddDays(1 - CInt(jan1.DayOfWeek))
Dim weeks = Enumerable.Range(0, 54).Select(Function(i) New With { _
Key .weekStart = startOfFirstWeek.AddDays(i * 7) _
}).TakeWhile(Function(x) x.weekStart.Year <= jan1.Year).[Select](Function(x) New With { _
x.weekStart, _
Key .weekFinish = x.weekStart.AddDays(4) _
}).SkipWhile(Function(x) x.weekFinish < jan1.AddDays(1)).[Select](Function(x, i) New WeekInfo With { _
.WeekStart = x.weekStart, _
.WeekEnd = x.weekFinish, _
.WeekNumber = i + 1 _
}).ToList()

Related

vb.net Set type () ()

I have class sObrazac in which I have
'''<remarks/>
<System.Xml.Serialization.XmlArrayItemAttribute("Primatelji", IsNullable:=false), _
System.Xml.Serialization.XmlArrayItemAttribute("P", IsNullable:=false, NestingLevel:=1)> _
Public Property StranaB() As sPrimateljiP()()
Get
Return Me.stranaBField
End Get
Set
Me.stranaBField = value
End Set
End Property
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"), _
System.SerializableAttribute(), _
System.Diagnostics.DebuggerStepThroughAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=true, [Namespace]:="http://e-porezna.porezna-uprava.hr/sheme/zahtjevi/ObrazacJOPPD/v1-1")> _
Partial Public Class sPrimateljiP
Private p1Field As Long
Private p2Field As String
Private p3Field As String
Private p4Field As String
.....
'''<remarks/>
Public Property P1() As Long
Get
Return Me.p1Field
End Get
Set
Me.p1Field = value
End Set
End Property
And now I'm setting the object what I have tried
Dim oPrimatelj As New sPrimateljiP
oPrimatelj.P1 = 1
oPrimatelj.P2 = 00019
oPrimatelj.P3 = 00019
oPrimatelj.P4 = 02994650199 ....
After setting that object I tried to push it into list and from it to array
Dim sList As New List(Of sPrimateljiP)
sList.Add(oPrimatelj)
oObrazac.StranaB = sList.ToArray
But as you know it will throw me
Value of type sPrimateljIP() cannot be converted to sPrimateljIP()()
I'm not quite familiar with two dimension arrays and I'm stuck here...
This may clear my question more. What is this element named P.
Note: I can't make schema, I need to adjust code to it.
Ok i found out what solution may be thanks to comment by Chetan. Use jagged array
Push list to jagged array and set it as object
Dim sList As New List(Of sPrimateljiP)
sList.Add(oPrimatelj)
sList.Add(oPrimatelj)
Dim jaggedArray()() As sPrimateljiP = New sPrimateljiP(0)() {sList.ToArray}
oObrazac.StranaB = jaggedArray

How to cast result back to generic list (using linq to object)?

Dim a As New List(Of EntityTableRow)
a = myTable1.TableRows
Dim lFinal2 = (From el In a Group el By Key = New With {Key el.Description, Key el.Activity, Key el.ServiceGroup, Key el.SubServiceGroup, Key el.ResourceGroup, Key el.Country, Key el.DCN, Key el.Workforce, Key el.RateType, Key el.LoadType} _
Into Group Select New With { _
.PageNum = "", _
.Description = Key.Description, _
.Activity = Key.Activity, _
.MonthCosts = (From k In Group.SelectMany(Function(g) g.MonthCosts.Keys).Distinct() _
Select New With {.Month = k, .Sum = Group.Sum(Function(g) _
If(g.MonthCosts.ContainsKey(k), g.MonthCosts(k), 0))}).ToDictionary(Function(i) i.Month, Function(i) i.Sum)})
I am not able to cast the above result back into the original object form from the below code:
Dim myTable1_grouped As New EntityDATATable(Of EntityTableRow)
myTable1_grouped.TableRows = CType(lFinal2, List(Of EntityTableRow))
original class is like below. The class has a number of more string properties, which I have omitted for this snippet. All those properties also are using in the grouping in above linq code.:
Public Class EntityTableRow
Public PageNum As Integer
Public Description As String
Public Activity As String
.....
.....
.....
Public MonthCosts As New Dictionary(Of Integer, Double)
End Class
The error I am getting is:
System.InvalidCastException was caught
Message="Unable to cast object of type 'WhereSelectEnumerableIterator2[VB$AnonymousType_12[VB$AnonymousType_010[System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String],System.Collections.Generic.IEnumerable1[Addin.EntityTableRow]],VB$AnonymousType_235[System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Collections.Generic.Dictionary2[System.Int32,System.Double]]]' to type 'System.Collections.Generic.List`1[Addin.EntityTableRow]'."
There are 2 things you have to do there:
Set your class name when creating the results:
Into Group Select New EntityTableRow With { _
instead of:
Into Group Select New With { _
And add ToList() to enumerate and get results into a List<EntityTableRow>:
myTable1_grouped.TableRows = CType(lFinal2.ToList(), List(Of EntityTableRow))

Use linq to combine 2 classes into a 3rd collection

If I have 2 classes and want to take 2 properties from each class, and combine them into a separate collection, how would this be done using linq?
Say the 2 classes are:
class guitars
public ID
public title
public manufacturer
end class
class drums
public ID
public title
public manufacturer
end class
I tried this, but it didn't work:
Private Interface Instruments
Property ID As String
Property name As String
End Interface
Dim results = From item In guitars _
Select New Instruments() With _
{ _
.ID = item.ID, _
.name = item.Title _
}
Dim results2 = From item In drums _
Select New Instruments() With _
{ _
.ID = item.ID, _
.name = item.Title _
}
Dim combined = results + results2
You can make it much simpler than that.
Just make both classes implement the IInstrument interface.
You can then write
guitars.Cast(Of IInstrument)().Concat(drums)
Union or Concat depending on wether or not you want to allow duplicates in the list.
http://msdn.microsoft.com/en-us/library/vstudio/bb763068.aspx
Dim Combined = results.Union(results2) ' no duplicates allowed
Dim Combined = results.Concat(results2) 'duplicates allowed
EDIT: Added Concat at the behest of MatthewWhited. He is totally right. The list is distinct according to the MSDN.

Implement Generic Interface via CodeDom

The CodeDom is not generating legal VB for me when I try to implement a generic interface.
Here is my VB code to generate the VB code.
Private Sub RunTest()
Dim compileUnit = New CodeCompileUnit
Dim ns As New CodeNamespace()
compileUnit.Namespaces.Add(ns)
ns.Imports.Add(New CodeNamespaceImport("System"))
ns.Imports.Add(New CodeNamespaceImport("System.Collections.Generic"))
Dim fooCollection = New CodeTypeDeclaration("FooCollection")
ns.Types.Add(fooCollection)
fooCollection.TypeAttributes = Reflection.TypeAttributes.Public
fooCollection.IsClass = True
fooCollection.BaseTypes.Add(New CodeTypeReference(GetType(System.Object)))
fooCollection.BaseTypes.Add(New CodeTypeReference( _
"System.Collections.Generic.IEnumerable" _
, New CodeTypeReference() {New CodeTypeReference("Foo")} _
))
Dim method = New CodeMemberMethod
fooCollection.Members.Add(method)
method.Attributes = MemberAttributes.Private
method.Name = "GetEnumerator"
method.ReturnType = New CodeTypeReference( _
"System.Collections.Generic.IEnumerable" _
, New CodeTypeReference() {New CodeTypeReference("Foo")} _
)
method.PrivateImplementationType = New CodeTypeReference( _
"System.Collections.Generic.IEnumerable" _
, New CodeTypeReference() {New CodeTypeReference("Foo")} _
)
Dim provider = New Microsoft.VisualBasic.VBCodeProvider
Dim options = New Compiler.CodeGeneratorOptions
Dim writer = New IO.StringWriter
provider.GenerateCodeFromCompileUnit(compileUnit, writer, options)
Console.WriteLine(writer.ToString)
End Sub
And that will generate:
Public Class FooCollection
Inherits Object
Implements System.Collections.Generic.IEnumerable(Of Foo)
Function System_Collections_Generic_IEnumerable`1_GetEnumerator() _
As System.Collections.Generic.IEnumerable(Of Foo) _
Implements System.Collections.Generic.IEnumerable(Of Foo).GetEnumerator
End Function
End Class
The problem is the name of the function. The tick mark in the function name doesn't make for a legal function name.
It seems that when using the PrivateImplentationType property of the CodeMethodMethod the Name property gets used as the name of the method you are implementing, not the name of the function.
How do you explicitly set the function name or at least how do I get it to be something legal?
To get a compilable output, just use ImplementationTypes: I just changed one line of your code (but I include a simple line for reference, and the corrected ReturnType):
method.Name = "GetEnumerator"
method.ReturnType = New CodeTypeReference( _
"System.Collections.Generic.IEnumerator" _
, New CodeTypeReference() {New CodeTypeReference("Foo")} _
)
method.ImplementationTypes.Add(New CodeTypeReference( _
"System.Collections.Generic.IEnumerable" _
, New CodeTypeReference() {New CodeTypeReference("Foo")} _
))
There doesn't seem to be a simple workaround using PrivateImplementationType. Microsoft's code in Microsoft.VisualBasic.VBCodeGenerator.GenerateMethod (which is in a Friend class so not easily overridden) caters for .'s, replacing them with _, but forgets to cater for ` in .NET 2.0-3.5 and (Of <type>) in 4.0. It is probably worth logging a bug at Connect, including pointing out the method name should be separately overridable compared to the method name on the interface being implemented.
You seem to need the functionality of PrivateImplementationType to support the non-generic GetEnumerator. Here is my simple adjustment of your original code to produce a single compilable library, with only warnings about empty code. This code still has "issues", such as the method.Attributes = MemberAttributes.Private being ignored where PrivateImplementationType is used...

JQGrid on ASP.Net MVC with VB.Net

I am trying to make a JQGrid for a simple table.
After following through with a VB translated version from
http://haacked.com/archive/2009/04/14/using-jquery-grid-with-asp.net-mvc.aspx
from
http://www.qa.downappz.com/questions/jqgrid-sorting-in-vb-net-mvc-app.html
I modified it to my own database and came up with this function
Public Function SelectGridData(ByVal sidx As String, ByVal sord As String, ByVal page As Integer, ByVal rows As Integer) As ActionResult
Dim context As New IssueDBEntities
Dim pageIndex As Integer = Convert.ToInt32(page) - 1
Dim pageSize As Integer = rows
Dim totalRecords As Integer = context.Issues.Count()
Dim totalPages As Integer = CInt(Math.Ceiling(CSng(totalRecords) / CSng(pageSize)))
Dim jsonData = New With { _
.total = totalPages, _
.page = page, _
.records = totalRecords, _
.rows = (From p In context.Issues _
Order By (p.ID & " " & sord) _
Select New With {.id = p.ID, .cell = _
{p.ID, p.Image_Path, p.Magazine_Type,p.Magazine_Path}}).ToArray()}
Return Json(jsonData, JsonRequestBehavior.AllowGet)
End Function
The grid does show up without any data, and the system throws an error
The error description says
"Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types."
Any help is appreciated, if this is due to some basic misunderstanding, please guide me, I am willing to do some hard work.
Thank you
Edit: The code that finally worked as per Oleg's Suggestion
Dim Simple_Object As IQueryable(Of Object)
Dim Second_Simple_Object As IQueryable(Of Object)
Dim My_Array As Array
Dim My_Second_Array As Array
Simple_Object = From p In Context.Issues _
Order By (p.ID & " " & sord) _
Select New With {p.ID, p.Image_Path, p.Magazine_Type, p.Magazine_Path}
My_Array = Simple_Object.ToArray()
Second_Simple_Object = From p In Context.Issues _
Order By (p.ID & " " & sord) _
Select New With {p.ID}
My_Second_Array = Second_Simple_Object.ToArray()
Dim My_Result(0) As My_Record_Type
For i = 0 To My_Array.GetLength(0) - 1
If i > 0 Then
ReDim Preserve My_Result(i)
End If
My_Result(i) = New My_Record_Type
My_Result(i).id = CInt(My_Second_Array(i).ID)
My_Result(i).Cell = {My_Array(i).ID.ToString, My_Array(i).Image_Path.ToString, _
My_Array(i).Magazine_Type.ToString, My_Array(i).Magazine_Path.ToString}
Next
Class My_Record_Type
Public id As Integer
Public Cell As String()
End Class
You try to fill rows property in one step. The problem is that you use Entity Framework which have some restrictions in the conversion of the data types. You can solve the problem if you first make query to get the items which you need without any data conversion and save intermediate results as List of items. After that you can make another LINQ Query where you include explicit conversion of p.ID to string. Moreover your current code don't use any paging of data. So the user will never seen more as the first page if you don't use loadonce: true.
It's difficult for me to write correct code in VB without debugging it. I use C# instead since last years. I recommend you to look at the answer for more information. It contains implementation of the server side filtering. If you don't need it and remove the corresponding code the rest code will be very short and I hope it will be easy to understand.
Here is complete sample of JQgrid with ASP.NET MVC 3 + C# (you can convert it to vb.net)
http://www.dotnetacademy.blogspot.in/2012/04/using-jqgrid-in-aspnet-mvc-3.html