complex lists within linq queries with select - vb.net

I have following linq to entities query, it looks good for compilation but giving me the following error when I run the code. And I want to get a very complex object, which is having some list of derived objects from EDM models. The lists in the below class are not directly from EDM models but they are derived classes from EDM to add more complexity to my problem. Here is the error message. Please help me in resolving this query. I have to get all the data that I want in one linq query thats what my lead is asking me for earlier I had one query for each component and I was adding them. But lead wants it in one query. Please help me in any ways link or code snippet or any suggestion please.
LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[LNI.WSAW.External.StayAtWork.EmployerAddress] ToList[EmployerAddress](System.Collections.Generic.IEnumerable`1[LNI.WSAW.External.StayAtWork.EmployerAddress])' method, and this method cannot be translated into a store expression.
And Here is the code:
Dim _requestrecord = (From r In Context.Requests.Include("Claims").Include("Employers").Include("EmployerContacts")
Where r.RequestId = RequestId AndAlso r.ManualClaimFlag = ManualClaim
Join c In Context.Claims On r.ClaimId Equals c.ClaimId Where c.ClaimNo.Equals(ClaimNumber)
Join e In Context.Employers On r.Employer.EmployerId Equals e.EmployerId Where e.EmplAccntNo.Equals(EmployerAccountNumber)
Join ec In Context.EmployerContacts On r.EmployerContactId Equals ec.EmployerContactId Where ec.SawGuid.Equals(EmployerContactGuid)
Select New RequestRecord() With { _
.Addresses = (From at In Context.EmployerAddressTypes
Join ea In Context.EmployerAddresses On at.AddressTypeId Equals ea.EmployerAddressType.AddressTypeId Where ea.EmployerId = r.Employer.EmployerId
Select New External.StayAtWork.EmployerAddress() With { _
.AddressLn1 = ea.AddressLn1,
.AddressLn2 = ea.AddressLn2,
.AddressLn3 = ea.AddressLn3,
.AddressType = at.Description,
.BusLocAddressId = ea.BuslocId,
.City = ea.City,
.Country = ea.Country,
.NewSwAddress = ea.NewSwAddressFlag,
.State = ea.St,
.Zip = ea.Zip,
.ZipExt = ea.ZipExt
}).ToList(),
.Employer = New EmployerBaisc() With { _
.EmployerId = e.EmployerId,
.EmployerName = e.EmplName
},
.Exspenses = (From td In Context.TransactionDates Where td.RequestId = RequestId
Join ex In Context.ExpenseTransactions On ex.TransactionDateId Equals td.TransactionDateId
Select New External.StayAtWork.RequestExpense() With { _
.ExpenseAmount = ex.ExpenseAmount,
.ExpenseDate = ex.TransactionDate.TransactionDt.ToString(),
.ExpenseItem = ex.ExpenseItem,
.ExpenseReason = ex.ExpenseReason,
.ExpenseType = ex.ExpenseSubTypeId
}).ToList(),
.Wages = (From td In Context.TransactionDates Where td.RequestId = RequestId
Join wt In Context.WageTransactions On wt.TransactionDateId Equals td.TransactionDateId
Select New External.StayAtWork.RequestWage() With { _
.DailyWage = wt.DailyWagePaidAmount,
.WorkDate = wt.TransactionDate.TransactionDt.ToString(),
.WorkHours = wt.WorkHours.ToString()
}).ToList(),
.Timeloss = (From ctl In Context.ClaimTimelosses
Join clms In Context.Claims On ctl.ClaimId Equals clms.ClaimId Where clms.ClaimId = c.ClaimId
Select New External.StayAtWork.ClaimTimeLoss() With { _
.ClaimNo = ctl.Claim.ClaimNo,
.FromDate = ctl.FromDt.ToString(),
.ToDate = ctl.ToDt.ToString()
}).ToList(),
.Files = (From rfs In Context.RequestFiles
Join reqs In Context.Requests On rfs.RequestId Equals reqs.RequestId Where reqs.RequestId = RequestId
Select New FileBasic() With { _
.FileId = rfs.RequestFileId,
.FileName = rfs.FileName,
.FromDiv = rfs.FromDiv
}).ToList(),
.UiSettings = (From ruis In Context.RequestUis
Join reqs In Context.Requests On ruis.RequestId Equals reqs.RequestId Where reqs.RequestId = RequestId
Select New External.StayAtWork.RequestUI() With { _
.ApfByFax = ruis.ApfByFaxFlag,
.ApfByMail = ruis.ApfByMailFlag,
.ApfLniHas = ruis.ApfLniHasFlag,
.ExpenseByFax = ruis.ExpenseByFaxFlag,
.ExpenseByMail = ruis.ExpenseByMailFlag,
.ExpenseLniHas = ruis.ExpenseLniHasFlag,
.JobByFax = ruis.JobByFaxFlag,
.JobByLni = ruis.JobByLniFlag,
.JobByMail = ruis.JobByMailFlag,
.LastDiv = ruis.LastDiv,
.requestId = ruis.RequestId,
.WageByFax = ruis.WageByFaxFlag,
.WageByMail = ruis.WageByMailFlag,
.WageLniHas = ruis.WageLniHasFlag
}).FirstOrDefault(),
.Request = New RequestBasic() With { _
.RequestId = RequestId,
.Comments = r.Comments,
.InjuredWorkerName = c.WorkerName,
.IsFixedSalary = r.FixedSalaryFlag,
.IsGraveyard = r.GraveyardFlag,
.IsManualClaim = r.ManualClaimFlag,
.JobDescriptBeforeInjury = r.JobDescriptBefore,
.JobDescriptLightDuty = r.JobDescriptLightduty,
.TrackHoursFlag = r.HoursTrackedFlag
}
}).FirstOrDefault()
Response.ResultData = _requestrecord
And here is the the class that I have to get:
Public Class RequestRecord
<DataMember()>
Public Property Request As RequestBasic
<DataMember()>
Public Property Employer As EmployerBaisc
<DataMember()>
Public Property Addresses As List(Of EmployerAddress)
<DataMember()>
Public Property Timeloss As List(Of ClaimTimeLoss)
<DataMember()>
Public Property Wages As List(Of RequestWage)
<DataMember()>
Public Property Exspenses As List(Of RequestExpense)
<DataMember()>
Public Property Files As List(Of FileBasic)
<DataMember()>
Public Property PaidDates As List(Of PaidDate)
<DataMember()>
Public Property UiSettings As RequestUI
End Class
Thanks in advance.

Related

Creating an object in VB.NET behaves differently on different SQL servers

I have following code which is behaving differently on different servers. In the below method if i write this line of code:
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId.Value, o.DsoId.Value, o.CustomerId.Value, o.CustomerPosition.Value)).ToList()
it returns result on one sql instance but does not return result on other sql instance.
However if i replace the above line with the following, it returns result on both sql instances.
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Could it be because sql server instances have different settings or it's something to do with the code itself?
--Function
Private Shared Function GetCustomerPositionsFromPaid(ByVal customerID As Integer, ByVal fundingYearID As Integer) As IEnumerable(Of CustomerPositionFromPaidDto)
Dim conditions = PredicateBuilder.True(Of vwCustomerPositionInPaid)()
conditions = conditions.And(Function(o) o.CustomerId.Equals(customerID))
conditions = conditions.And(Function(o) o.FundingYearId.Equals(fundingYearID))
conditions = conditions.And(Function(o) o.DsoId.HasValue)
'Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId.Value, o.DsoId.Value, o.CustomerId.Value, o.CustomerPosition.Value)).ToList()
'Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).ToList().Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId, o.DsoId, o.CustomerId, o.CustomerPosition)).ToList()
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Return customerPositionsFromPaid
End Function
--Select All
Public Shared Function [SelectAll](ByVal conditions As Expression(Of Func(Of T, Boolean))) As IEnumerable(Of T)
Return [SelectAll]().Where(conditions)
End Function
Public Shared Function [SelectAll]() As IQueryable(Of T)
Return Table
End Function
Private Shared ReadOnly Property Table() As Table(Of T)
Get
Return Context.GetTable(Of T)()
End Get
End Property
I manage to solve the above by writing the following code. Looks like because customerid and fundingyearid are nullable objects, i had to use .Value attribute but still not sure why the previous code will work on one server and not on the other one.
Private Shared Function GetCustomerPositionsFromPaid(ByVal customerID As Integer, ByVal fundingYearID As Integer) As IEnumerable(Of CustomerPositionFromPaidDto)
Dim conditions = PredicateBuilder.True(Of vwCustomerPositionInPaid)()
conditions = conditions.And(Function(o) o.CustomerId.Equals(customerID.Value))
conditions = conditions.And(Function(o) o.FundingYearId.Equals(fundingYearID.Value))
conditions = conditions.And(Function(o) o.DsoId.HasValue)
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Return customerPositionsFromPaid
End Function

Need To Return GroupBy Data With Counts But Selecting Multiple Fields Using LINQ

Okay, I'm sure this is simple for someone but it is starting to cause me to tear my hear out so I apologise in advance if this seems like a simple question:
I have the following class:
Public Class Ticket
Public Property ticket_id As String
Public Property ticket_assignee As String
Public Property ticket_email As String
End Class
I am trying to use LINQ to group my list by the ticket_email field but allow me to get the ticket_assignee field and count of each group.
So for example:
For each email address, return me the assignee name and how many tickets in that email group like below:
'fred#someplace.com' = Fred, 4
'joe#someplace.com' = Joe, 2
'bob#someplace.com' = Bob, 8
etc...
I am still trying to get my head around LINQ and would love to understand it more. Any help would be appreciated thankyou.
A Query Syntax Solution:
Sub Main
Dim q = from entry in Ticket.GetTickets
group entry by entry.ticket_assignee Into NewGroup = Group, Count()
select new with{
.Assignee = NewGroup.Select(function(x) x.ticket_assignee).First,
.Email = NewGroup.Select(function(x) x.ticket_email).First,
.Count = Count}
'q.dump()
End Sub
' Define other methods and classes here
Public Class Ticket
Public Property ticket_id As Integer
Public Property ticket_assignee As String
Public Property ticket_email As String
Public Shared Function GetTickets as list(of Ticket)
Return New List(of Ticket) From {New Ticket With {.ticket_id = 1, .ticket_assignee = "Fred", .ticket_email = "fred#ticket.de"},
New Ticket With {.ticket_id = 2, .ticket_assignee = "Fred", .ticket_email = "fred#ticket.de"},
New Ticket With {.ticket_id = 3, .ticket_assignee = "Fred", .ticket_email = "fred#ticket.de"},
New Ticket With {.ticket_id = 4, .ticket_assignee = "Anna", .ticket_email = "Anna#ticket.de"},
New Ticket With {.ticket_id = 5, .ticket_assignee = "Anna", .ticket_email = "Anna#ticket.de"},
New Ticket With {.ticket_id = 6, .ticket_assignee = "Jack", .ticket_email = "Jack#ticket.de"}}
End Function
End Class
Gives you:
For learning Linq I highly recommend LinqPad. You can choose VB.NET Program, copy my code, uncomment the .dump() line and run it.
Dim tickets As New List(Of Ticket)
For i = 1 To 3
tickets.Add(New Ticket With {.ticket_id = i.ToString, .ticket_email = "a", .ticket_assignee = "me"})
Next
For i = 4 To 6
tickets.Add(New Ticket With {.ticket_id = i.ToString, .ticket_email = "b", .ticket_assignee = "me2"})
Next
Dim group = tickets.GroupBy(Function(x) x.ticket_assignee).Select(Function(y) New Tuple(Of String, Integer)(y.First.ticket_assignee, y.Count))

How convert result of linq query to List(Of T)

I'm using EntityFrameWork 5 in VB MV4 project.
I have a database built from EntityFramework diagram (model firt as opposed to code first)
I have a ViewModel X, containing a List(ofT) T being one on my Entity
When I open my web application (on the browser) I ask a controller to give me the ViewModel X as a Json object that I use to populate a MVVC (knockout model) using the Knockout JS Mapping pluggin.
When I ask for the model, I populate it using code similar to what is shown below
Public Class DataServiceController
Inherits System.Web.Mvc.Controller
<Authorize()> _
Public Function RetrieveData() As JsonResult
Dim model As ViewModelX
model = New ViewModelX
'=====================================
' Resources and Tools
'=====================================
Dim fetchedResourceAndToolsQuery = From a In db.ResourceAndTools
Where a.ProfileId = profile.ProfileId Select a
For Each eachRes In fetchedResourceAndToolsQuery
Dim res As ResourceAndTools = New ResourceAndTools
res.Name = Trim(eachRes.Name)
res.URL = Trim(eachRes.URL)
res.Target = eachRes.Target
res.ResourceId = eachRes.ResourceId
model.ResourceAndTools.Add(res)
Next
Return Json(model, JsonRequestBehavior.AllowGet)
Everthing works great! Except... And here's the question
As mentionned above, ViewModelX contains a List(of T) T being ResourceAndTools
Is there a was to copy (clone, load, not sure of the term) the content of fetchedResourceAndToolsQuery (Result of the Linq Query) to model.ResourceAndTools (List(of T)) without instantiating a new object and copying the properties like I'm doing.
I've seached (Cloning, Deep Copying, Shallow Copying, etc.) The closest I came to a solution was some explanation on how to deep copy an object but it relied on serialisation, it did not work because not all properties of a Entity Framework object are serialisable.
Any help is appreciated
Thank you
Like this?
model.ResourceAndTools = (
From a In db.ResourceAndTools
Where a.ProfileId = profile.ProfileId
Select New ResourceAndTools() With { _
.Name = Trim(a.Name), _
.URL = Trim(a.URL), _
.Target = a.Target, _
.ResourceId = a.ResourceId}).ToList()
Following your comment, perhaps you could do,
Dim dataList = (
From a In db.ResourceAndTools
Where a.ProfileId = profile.ProfileId
Select New With
{
.Name = Trim(a.Name),
.URL = Trim(a.URL),
.Target = a.Target,
.ResourceId = a.ResourceId
}).ToList()
model.ResourceAndTools = dataList.ConvertAll(Function(data)
Return New ResourceAndTools() With
{
.Name = data.Name,
.Url = data.Url,
.Target = data.Target,
.ResourceId = data.ResourceId
}
End Function)

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))

LINQ query to group data between two list collections, populating a nested object (VB.Net)

I have these objects:
Public Class MakeInfo
Public Property Name As String
Public Property Description As String
Public Property Stock As StockInfo
End Class
Public Class ModelInfo
Public Property Make As String
Public Property Name As String
Public Property Description As String
Public Property Stock As StockInfo
End Class
Public Class StockInfo
Public Property Count As Integer
Public Property MinPrice As Double
End Class
Using LINQ I need to take a List(Of MakeInfo) and a List(Of ModelInfo) and aggregate the StockInfo from ModelInfo into the List(Of MakeInfo).
So for each MakeInfo I will have a total count of all stock where MakeInfo.Name = ModelInfo.Make, and also a minimum price.
I think it's going to be something like this, but I'm having trouble accessing the nested object and not sure if it's going to be possible with a single query. I've tried a few variations, but here's where I'm up to:
newList = From ma In makeData _
Group Join mo In modelData _
On ma.Name Equals mo.Make _
Into Group _
Select New MakeInfo With {.Name = m.Name, _
.Description = m.Description, _
.Stock = ?}
If you are actually trying to modify the original MakeInfo objects, you should stop the query with the group. newList will have each make paired with the group of models of that make. You can iterate through newList, and for each make, aggregate the models into the StockInfo for the make.
Dim newList = From ma In makeData _
Group Join mo In modelData _
On ma.Name Equals mo.Make _
Into Group
For Each g In newList
g.ma.Stock = g.Group.Aggregate(
New StockInfo() With {.MinPrice = Double.NaN},
Function(si, model)
Return New StockInfo With {
.Count = si.Count + 1,
.MinPrice = If(Double.IsNaN(si.MinPrice) OrElse
model.Stock.MinPrice < si.MinPrice,
model.Stock.MinPrice,
si.MinPrice)}
End Function)
Next
If you actually want new instances, just change the loop to create a new item instead of modifying the existing make.
Dim results As New List(Of MakeInfo)()
For Each g In newList
Dim newMake As New MakeInfo()
newMake.Name = g.ma.Name
newMake.Description = g.ma.Description
newMake.Stock = g.Group.Aggregate( same as before )
results.Add(newMake)
Next
I eventually found the right way to do this and it doesn't require loop iteration:
Dim new_makes = From ma In makes
Join mo In models On mo.Make Equals ma.Name
Group By ma.Name, ma.Description
Into TotalCount = Sum(mo.Stock.Count), LowestPrice = Min(mo.Stock.MinPrice)
Select New MakeInfo With {.Name = Name, _
.Description = Description, _
.Stock = New StockInfo With {.Count = TotalCount, .MinPrice = LowestPrice}}
I was certain that it would be possible.