Anonymous type and LINQ and casting - vb.net

I'm pretty stuck on this anonymous type from LINQ business. It's a consequence of working through an answer to a previous question, but sadly I just havent the brain power to get this to work at all.
I'm returning a limited list of events that are connected to each person. The source is Entity Framework where I'm still battling to get criteria limited results from a navigation property. The code below is my translation from Nicholas Butler's answer. However, I can't find any way to adapt the anonymous type. Casts don't seem to work - or I just haven't a clue (likely). Can anyone help please?
Dim test = context.persons.Where(Function (r) r.personActive).Select(Function (o) New With { _
.person = o, _
.events = o.events.Where( Function(e) e.eventDateTime > startdate) _
})
Dim Res = New ObservableCollection(Of person )
For Each person In test
Res.Add(person)
Next
Gives me:
Error 2 Value of type '<anonymous type> (line 53)' cannot be converted to 'PersonEntity.person'. E:\Dropbox\Work Experimental\PersonEntity- Copy\PersonEntity\personRepository.vb 61 29 PersonEntity
I've gotten further with this code but I still cannot have the attached events as I get yet another error with the casting, this time of events. Generic List to ObservableList doesn't convert apparently. It seems an incredible way round to answer my original question!
Dim test = context.persons.Where(Function(r) r.personActive).Select(Function(o) New With { _
.person = o, _
.events = o.events.Where(Function(e) e.eventDateTime > startdate) _
})
Dim Res = New ObservableCollection(Of person)
For Each t In test
Dim r As New person
r = t.person
r.events = t.events
Res.Add(r)
Next
Return Res

Function(o) New With { _
.person = o, _
.events = o.events.Where(Function(e) e.eventDateTime > startdate) _
}
This returns an anonymous type, not a Person. Did you mean to Add its person property*?
For Each o In test
Res.Add(o.person)
Next

Related

LINQ to XML - select to a strongly typed object (VB)

This is not a big issue but it's bugging me. I know how to select into a strongly typed collection (List(Of T), but I can't find a tidy way of doing this for an object that is not a List.
This works:
Dim x = From a In response...<artist> _
Select New MBArtistInfo With {.MBID = a.#id, .Name = a.<name>.Value, .Gender = a.<gender>.Value}
Return x(0)
but it is annoying to have to do that.
I have seen a C# solution elsewhere along the lines of:
var x = from a In response...<artist>
select new MBArtistInfo
{
MBID = etc
but I can't convert this to VB.
Has anyone done this?
Just skip class name:
Dim x = From a In response...<artist> _
Select New With { .MBID = a.#id, .Name = a.<name>.Value, .Gender = a.<gender>.Value }
But it will give you IEnumerable(Of T), where T is an anonymous type. You should not return objects like that from your methods:
For example, an anonymous type cannot be used to define a method
signature, to declare another variable or field, or in any type
declaration. As a result, anonymous types are not appropriate when you
have to share information across methods.
Edit
To get only one element from collection use First/FirstOrDefault methods:
Dim x = (From a In response...<artist> _
Select New With { .MBID = a.#id, .Name = a.<name>.Value }).FirstOrDefault();

Entity Framework 5 is sending back the wrong data

I have a very serious issue with EF sending back the wrong data. I know its wrong because I can run the same query against the same table in management studio and get a completely different result.
I did research the problem and found that some people were able resolve the issue by adding:
*DbContextSummary.Refresh(RefreshMode.StoreWins, result);*
When I try adding that I get this error:
The element at index 0 in the collection of objects to refresh has a null EntityKey property value or is not attached to this ObjectStateManager.
After I got that error I tried to do: DbContextSummary.Attach(result) and I received another error.
What is the proper solution and why does this happen?
Relevant Code (without the refresh call):
Private _dbContextSummary As BudgetEntities
Public ReadOnly Property DbContextSummary() As BudgetEntities
Get
If _dbContextSummary Is Nothing Then
_dbContextSummary = New BudgetEntities
End If
Return _dbContextSummary
End Get
End Property
<WebMethod()> _
Public Function GetSummaryData(ByVal month As String, ByVal year As String, ByVal expenseLine As String, ByVal organization As String) As List(Of SummaryModel)
Dim result As List(Of SummaryModel) = Nothing
result = (From s In DbContextSummary.FPRs _
Where s.FY = year _
Where s.Month = month _
Where s.FPRLine = expenseLine _
Where s.VP = organization
Group s By s.MgrID, s.ProgAdm, s.FinanceNumber, s.FinanceNumberName Into g = Group _
Order By g.FirstOrDefault.MgrLastName, g.FirstOrDefault.ProgAdm Ascending
Select New SummaryModel With { _
.Actual = g.Sum(Function(a) a.Actual), _
.Plan = g.Sum(Function(p) p.Plan), _
.YTDActual = g.Sum(Function(ya) ya.YTDActual), _
.YTDPlan = g.Sum(Function(yp) yp.YTDPlan), _
.FinanceNumber = g.FirstOrDefault.FinanceNumber, _
.FinanceNumberName = g.FirstOrDefault.FinanceNumberName, _
.MgrLastName = g.FirstOrDefault.MgrLastName + ", " + g.FirstOrDefault.MgrFirstName, _
.PlanYearTotal = g.FirstOrDefault.PlanYearTotal, _
.ProgAdm = g.FirstOrDefault.ProgAdm _
}).ToList()
Return result
End Function
What is the proper solution and why does this happen?
Simply put, there is no proper solution in your scenario. Refresh is not applicable at all after you have performed a projection (select new) into a type (SummaryModel) that isn't an entity. Your result collection does not contain entities but SummaryModels. You neither can apply Refresh nor Attach to this collection or its elements. Both methods are intended to work with model entities: Refresh updates properties of an already attached entity from the data store and Attach adds an entity to the context in state Unchanged.
I suggest that you open a new question and describe why you think that "EF is sending back the wrong data" and try to solve this problem. It's unlikely that re-loading provides correct data when loading delivers a wrong result.

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

Linq to SQL Cast Exception

I'm starting my first Linq to SQL project in VB.NET (which I am also new to).
I am trying to Delete an entity but am having trouble with an InvalidCastException. The debugger breaks at the Next statement in the ForEach loop.
My entity class is called Material.
Any help would be very much appreciated.
Thanks,
Kenneth
Dim materialsTable As Table(Of Material) _
= (New DataContext("Server=.\SQLEXPRESS; Database=Materials; Trusted_Connection=yes;") _
.GetTable(Of Material)())
Dim materialsToDelete = (From x In materialsTable _
Where x.MaterialName = aMaterial.MaterialName _
Select x)
If (materialsToDelete Is Nothing) Then Return
If (materialsToDelete.Count = 0) Then Return
For Each m As Material In materialsToDelete
materialsTable.DeleteOnSubmit(m)
Next
materialsTable.Context.SubmitChanges()
Make sure you actually run the query with a .ToList()
Also, go with a straightforward DataContext if you can. I've not seen your implementation of the DC anywhere.
Dim db as new NorthwindDataContext()
Dim materialsToDelete = (From x In db.Materials _
Where x.MaterialName = aMaterial.MaterialName _
Select x)
You actually don't need to loop to delete them.
materialsTable.DeleteAllOnSubmit(materialsToDelete)
materialsTable.Context.SubmitChanges()

how to group by over anonymous type with vb.net linq to object

I'm trying to write a linq to object query in vb.net, here is the c# version of what I'm trying to achieve (I'm running this in linqpad):
void Main()
{
var items = GetArray(
new {a="a",b="a",c=1}
, new {a="a",b="a",c=2}
, new {a="a",b="b",c=1}
);
(
from i in items
group i by new {i.a, i.b} into g
let p = new{ k = g, v = g.Sum((i)=>i.c)}
where p.v > 1
select p
).Dump();
}
// because vb.net doesn't support anonymous type array initializer, it will ease the translation
T[] GetArray<T>(params T[] values){
return values;
}
I'm having hard time with either the group by syntax which is not the same (vb require 'identifier = expression' at some places, as well as with the summing functor with 'expression required' )
Thanks so much for your help!
You can create an array of type Object in VB.NET that can contain objects of any type, including anonymous types. The compiler will correctly infer that the same anonymous type is to be used provided you keep the same field name, types, and order of fields.
I ran this code in LinqPad to get the results you are looking
Dim items As Object() = { _
New With {.a="a",.b="a",.c=1}, _
New With {.a="a",.b="a",.c=2}, _
New With {.a="a",.b="b",.c=1} _
}
Dim myQuery = From i In items _
Group By i.a, i.b into g = Group _
let p = New With { .k = g, .v = g.Sum(Function(i) i.c)} _
where p.v > 1 _
select p
myQuery.Dump