Select By Key Values from a LINQ Query in a view - vb.net

I am trying to grab each key value from a LINQ Query and pull them into my view. The LINQ query looks like this:
Public Property ByVDN As IEnumerable
Get
Dim valQ = (From scr In Var.db.CareSideA.ScriptCrossReferences
Join s In Var.db.CareSideA.Scripts On s.ScriptID Equals scr.ScriptID
Join ms In Var.db.CareSideA.MasterScripts On s.MasterScriptID Equals ms.MasterScriptID
Join svce In Var.db.CareSideA.Services On svce.SkillTargetID Equals scr.ForeignKey
Join p In Var.db.CareSideA.Peripherals On svce.PeripheralID Equals p.PeripheralID
Join sm In Var.db.CareSideA.ServiceMembers On svce.SkillTargetID Equals sm.ServiceSkillTargetID
Join sg In Var.db.CareSideA.SkillGroups On sm.SkillGroupSkillTargetID Equals sg.SkillTargetID
Where s.Version = ms.CurrentVersion And scr.TargetType = 1 And svce.PeripheralNumber = Value
Select New With {Key .Service = svce.PeripheralNumber,
Key .ScriptName = ms.EnterpriseName,
Key .Peripheral = p.EnterpriseName,
Key .SkillMapping = sg.PeripheralNumber,
Key .LatestVersion = s.Version,
Key .Created = s.DateTime,
Key .Author = s.Author}).ToList
Return valQ
End Get
Set(value As IEnumerable)
End Set
End Property
Now this does return results but they look like this:
Ideally I'd like to be able to do this:
<table>
For Each Item In Model.ByVDN
Dim i = Item
<tr>
<td>#Html.DisplayFor(Function(m) i.Service)</td>
<td>#Html.DisplayFor(Function(m) i.ScriptName)</td>
<td>#Html.DisplayFor(Function(m) i.Peripheral)</td>
Next
etc...

You can't pass about anonymous objects. Well, you can, but it is not strongly typed. You'll have to define a class with these properties, create IEnumerable of instances of that class and pass that Enumerable to the view. There is no other way.
UPD: see similar question: passing linq select query to the method

Related

Databinding list of objects to a data grid view

I have this manual adding of data or row in the grid and I would like to ask some idea on how to implement data binding in vb.net.
memberGrid.Rows.Clear()
For Each m As Member In members
Dim row As Object() = {m.MemberId, EntityHelper.FullName(m.Person.FirstName, m.Person.SurName),
WorkoutLogic.GetLastWorkoutDateDisplay(m.MemberId, AppRuntime.Workouts),
LogicService.GetMembershipStatus(m.MembershipHistories),
m.Person.Mobile}
memberGrid.Rows.Add(row)
Next
Try something like
memberGrid.DataSource = (From m In members
Select New With { Id = m.MemberId,
FullName = EntityHelper.FullName(m.Person.FirstName, m.Person.SurName),
LastWorkout = WorkoutLogic.GetLastWorkoutDateDisplay(m.MemberId, AppRuntime.Workouts),
Status = LogicService.GetMembershipStatus(m.MembershipHistories),
Mobile = m.Person.Mobile }).ToList()
Change the names before the ='s to match the names of your columns.

VB.NET Linq Left Join using Query Syntax

I have a list of applications. Each application may or may not have a support record associated with it.
The only way I can join is to take the App Title and see if its equal to the LookupValue of Support(Product). But to get that property, i have to cast to a FieldLookupValue. When there is no associated support record, that is where the null reference error gets thrown on .MoveNext() inside the Linq query. Below is what currently works for apps that have associated support, but throws the error when they don't.
Dim q =
From a In apps.AsEnumerable()
Group Join s In support.AsEnumerable()
On a("Title").ToString() Equals CType(s("Product"), FieldLookupValue).LookupValue
Into Group
From ajs In Group.DefaultIfEmpty()
Select New With {
.Name = a("Title"),
.SupportEnd = IIf(ajs Is Nothing, Nothing, ajs("End"))
}
Any way I could compare anonymous types in the On Statement? I can't seem to get the syntax right on that, or maybe its not possible. I feel that could fix the null reference error. My unsuccessful attempt returned Equals cannot compare type with the value of type
Dim q =
From a In apps.AsEnumerable()
Group Join s In support.AsEnumerable()
On
(New With {Key .AppName = a("Title").ToString()}) Equals
(New With {Key .AppName = IIf(s Is Nothing, "nada", CType(s("Product"), FieldLookupValue).LookupValue)})
Into Group
From ajs In Group.DefaultIfEmpty()
Select New With {
.Name = a("Title"),
.SupportEnd = IIf(ajs("End") Is Nothing, Nothing, ajs("End"))
}
Any ideas as to how to get this join to work using one of the two failed methods above would be great.
Once I created a dummy default object based on a random selection from the support list (i chose index 0), I used that to compare to as shown. Then just used the Let statement to have a boolean easily accessible when selecting.
Dim q =
From a In apps.AsEnumerable()
Group Join s In support.AsEnumerable()
On a("Title").ToString() Equals CType(s("Product"), FieldLookupValue).LookupValue
Into Group
From ajs In Group.DefaultIfEmpty(support(0))
Let NoSupport As Boolean = IIf(ajs.Equals(support(0)), True, False)
Select New With {
.Name = a("Title"),
.SupportEnd = IIf(NoSupport, "No Support", ajs("End"))
}

How to return distinct result in linq to collection

Below query result duplicates of class code.
cboFilterValues.DataSource = (From i In allDetails Select New LookUpItem With {.ItemText = i.ClassCode, .ItemValue = i.ClassCode} Distinct).ToList()
Can any one suggest me how i could achieve distinct result for above query. I need result set as IList(Of LookupItems)
Thank You
Your Distinct is not working because (presumably - you didn't provide the code) you have not overridden the Equals and GetHashCode methods in your LookUpItem class, so instances are being compared using reference equality. If you implement those methods, the Distinct should work:
Public Overrides Function Equals(o As Object) As Boolean
If o Is Nothing OrElse Not Me.GetType().Equals(o.GetType()) Then Return False
Dim other = DirectCast(o, LookUpItem)
Return Me.ItemText = other.ItemText ' or some other fields
End Function
Public Overrides Function GetHashCode() As Integer
Return Me.ItemText.GetHashCode() ' or some other fields
End Function
Alternatively, you could modify your query a little, since you are only using the ClassCode property from allDetails, and put the distinct there (assuming that ClassCode is a String, or something else that uses value equality):
cboFilterValues.DataSource = (
From i In (From d In allDetails Select d.ClassCode Distinct)
Select New LookUpItem With {.ItemText = i, .ItemValue = i}
).ToList()
cboFilterValues.DataSource = (From x In (From i In allDetails Select i Distinct) Select New LookUpItem With {.ItemText = x.ClassCode, .ItemValue = x.ClassCode}).Tolist
I assuming what you have above doesn't work because of some problem with the select new, this should get round it if that's the problem.
Tim

Entity Framework left Join two databases

I am in need of joining a list to a database query using entity framework.
Basically, I have two databases where I need to outer join a table from one database to a table in another database.
In order to do this, I thought of getting a list from database one and then left join it to the query of the second query.
The problem is, I have to return the result as an IQueryable, so the consumer of the method can do additional filtering on the query before it being executed.
I have tried two different methods:
Option 1:
Public Shared Function List() As IQueryable(Of ContractEquipment)
' Get Subcontractors from Database 1
Dim subcontractors As List(Of SubContractor) = GetSubContractorList().ToList()
' Query Database 2
Return (From c In DB.ContractEquipments
Select New With {
.ContractID = c.ContractID,
.EquipmentID = c.EquipmentID,
.Inactive = c.Inactive,
.SubContractorName = (From x In subcontractors Where c.SubContractorID = x.SubContractorID Select x.Name).FirstOrDefault()
})
End Function
Option 2:
Public Shared Function List() As IQueryable(Of ContractEquipment)
' Get Subcontractors from Database 1
Dim subcontractors As List(Of SubContractor) = GetSubContractorList().ToList()
' Query Database 2
Return (From c In DB.ContractEquipments
Group Join s in subcontractors on c.SubContractorID equals s.SubContractorID into tblSubContractors = Group
Select New With {
.ContractID = c.ContractID,
.EquipmentID = c.EquipmentID,
.Inactive = c.Inactive,
.SubContractorName = tblSubContractors.Select(Function(z) z.Name).FirstOrDefault()
})
End Function
I keep getting the same error:
"Unable to create a constant value of type . Only primitive types ('such as Int32, String, and Guid') are supported in this context."
Anybody have any suggestions?
Okay, I found a workaround.
Created a View in database 2:
CREATE VIEW dbo.ViewContractEquipment
AS SELECT e.ContractEquipmentID, s.Name as SubContractorName
FROM dbo.ContractEquipments AS e
LEFT OUTER JOIN DB2.dbo.SubContractors AS s ON e.SubContractorID = s.SubContractorID
I then added the view to my query and joined it with the main table:
Return (From d In DB.ViewContractEquipments
Join c in DB.ContractEquipments ON c.ContractEquipmentID equals d.ContractEquipmentID
Select New With {
.ContractID = c.ContractID,
.EquipmentID = c.EquipmentID,
.Inactive = c.Inactive,
.SubContractorName = d.SubContractorName
})
Not elegant, but it works!

How do I return a single entity with a self-join using LINQ (in VB.NET)?

I am trying to return a single entity class ("category") with a LINQ query (in VB.NET) with a JOIN, but it isn't working. I think it's either because:
I'm getting an IEnumerable resultset (of 1) OR
I'm getting more than just the first-table-in-the-join's
columns back
because I get this invalid type cast exception:
Unable to cast object of type 'System.Data.Linq.DataQuery`1[category]'
to type 'category'.
Here is SQL that does what I want (note how I don't want any columns from the joined table):
select subcat.*
From category as cat
join category as parentcat On cat.cat_id = cat.parent_cat_id
Where parentcat.cat_url = 'dogs'
And cat.cat_url = 'poodles'
Here's the LINQ code I have that works in LINQPad:
dim q = From cat In categories _
Join parentcat In categories On parentcat.cat_id Equals cat.parent_cat_id _
Where parentcat.cat_url.ToLower = "dogs" _
And cat.cat_url.ToLower = "poodles" _
Select categories.SingleOrDefault(function(c) c.cat_id = cat.cat_id)
q.dumb
But this doesn't work in my "CategoryRepository" function in VB.NET:
Public Function GetCategoryByURL(ByVal strCatURL As String, ByVal strSubCatURL As String) As category Implements ICategoryRepository.GetCategoryByURL
Return From cat In db.categories _
Join parentcat In db.categories On parentcat.cat_id Equals cat.parent_cat_id _
Where parentcat.cat_url.ToLower = strCatURL.ToLower _
And cat.cat_url.ToLower = strSubCatURL.ToLower _
Select db.categories.SingleOrDefault(Function(C) C.cat_id = cat.cat_id)
End Function
How do I make it to return a single instance of the "category" class? (I need it that way because I have this same function overloaded that returns a single instance ... and that works!) I have verified that the database is correct and it should return the "poodles" category.
I'm new to LINQ, so I'm sure there is something very obvious that I'm doing incorrectly, so I'd appreciate any help!
You query categories and you return the statement db.categories.SingleOrDefault(Function(C) C.cat_id = cat.cat_id) for each row in the result set. This is always an IQueryable even though it may have 0 or 1 results. You must do SingleOrDefault() over the whole query:
Dim query = From cat In db.categories _
Join parentcat In db.categories On parentcat.cat_id
Equals cat.parent_cat_id _
Where parentcat.cat_url.ToLower = strCatURL.ToLower _
And cat.cat_url.ToLower = strSubCatURL.ToLower _
Select cat
Return query.SingleOrDefault()