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!
Related
I have 2 tables:
Room_Type (ID_Room_Type, Name_Room_Type)
Room_Room (ID_Room_Type, Number_Room)
How to place a new column Temp in the RoomType table that will take its value as the sum of the rooms from the Room_Room table.
This code does not work :
Private Sub SimpleButton1_Click(sender As Object, e As EventArgs) Handles SimpleButton1.Click
Dim Db As New HotelEntities
Dim s = (From I In Db.Room_Type Select I.ID_Room_Type, I.Name_Room_Type, ColumnTemp = GetTotal_Room(I.ID_Room_Type)).ToList()
Me.DataGridView1.DataSource = s
End Sub
Private Function GetTotal_Room(id_room_type As Int32) As Int32
Dim Db As New HotelEntities
Return (From I In Db.Room_Room Where I.ID_Room_Type = id_room_type).Count
End Function
Message Error :LINQ to Entities does not recognize the method 'Int32
GetTotal_Room(Int32)' method, and this method cannot be translated
into a store expression.
I had a similar problem and I solved it by extracting the list first and then applying linq over it. You can try by altering your code as below.
Dim Db As New HotelEntities
Dim roomTypeList = Db.Room_Type.ToList()
Dim s = (From I In roomTypeList
Select I.ID_Room_Type, I.Name_Room_Type,
ColumnTemp = GetTotal_Room(I.ID_Room_Type)).ToList()
Me.DataGridView1.DataSource = s
Entity Framework will generate Linq query expressions to valid sql query.
As error message explain EF doesn't know how to convert your method GetTotal_Room to valid sql query.
Instead you can get required result from one query, without extra function.
From roomRoom In db.Room_Room
Join roomType In db.Room_Type On roomRoom.ID_Room_Type Equals roomType.ID_Room_Type
Select New With { roomRoom.ID_Room_Type, roomType.Name_Room_Type } Into roomtypes
Group roomtypes By roomtypes Into grouptypes
Select New With
{
Id = grouptypes.Key.ID_Room_Type,
Name = grouptypes.Key.Name_Room_Type,
Total = grouptypes.Count()
}
As additional notice, I don't know context of your application, but based on given sample, I think you can remove some prefixes and suffixes in table and column names
RoomType
Id
Name
Room
TypeId -- reference to RoomType.Id
I am new to Entity Framework and I have this SQL query:
SELECT
WarningTypes.WarningTypeID, WarningTypes.WarningDescription,
WarningTypes.WarningArDescription, WarningReasons.ReasonName
FROM
WarningTypes
INNER JOIN
WarningReasons ON WarningTypes.WarningReasonID = WarningReasons.ID
and I need to convert this to be entity frame work so I Wrote this vb.net code:
Public Function selectAllWarningTypes() As System.Linq.IQueryable
'Dim dt As New DataTable
'wt.selectAllWarningTypes(dt)
Dim query = _
From warningTypes In objSRSEntities.WarningTypes _
From warningReasons In objSRSEntities.WarningReasons _
.Where(Function(wr) wr.ID = warningTypes.WarningReasonID) _
Select warningTypes = warningTypes, warningReasons = warningReasons
Return query
End Function
The problem is: this run time error returned when I set result in gridview:
Data binding directly to a store query (DbSet, DbQuery, DbSqlQuery, DbRawSqlQuery) is not supported
Thanks.
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
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()
I have a LINQ to sql statement that joins 2 tables. I would like to add a order by clause on one of the columns. However the order by clause does not seem to take effect at all.
Could you please suggest the right syntax in VB.net to achieve order by in the following:
Dim query = From dtIt In dbsomecontext.mytable
Join dtIl In dbsomecontext.anothertable On dtIt.ItemID Equals dtIl.ItemID
Where dtIl.IsAvailable = True
Order By dtIt.manufacturer
Select New With {
.Alpha = UCase((dtIt.manufacturer).Substring(0, 1))
}
Dim dtManufacturer As DataTable = csLINQOperations.LINQToDataTable(query)
Return dtManufacturer
Have you put a break point on the line where to Dim dtManufacturer ?
I created some sample classes to repersent your data objects as you've defined it.
Dim linqQuery = From dtIT In myTables _
Join dtIL In otherTables On dtIT.ItemID Equals dtIL.ItemID _
Where dtIL.IsAvaliable = True _
Order By dtIT.Manufacturer Ascending _
Select New With {.Alpha = UCase((dtIT.Manufacturer).Substring(0, 1))}
Now, when I have a break point on the line after this LINQ Query I can inspect the object linqQuery by using "linqQuery.ToList" and see the order of the data. It does infact order the output in an ordered fashion, based on the Manufacturer name.
Why is it that you think your code is not ordering the data? Using the Break Points and Watch, inspect your "query" object (using "query.ToList" in the Quick Watch) and see if the results are ordered correctly.
Yes, I figured the results were not ordered by "QuickWatch"ing dtManufacturer in the line :
Dim dtManufacturer As DataTable = csLINQOperations.LINQToDataTable(query)
Now, I have changed the query to as follows and it works :
Dim query = From dtIt In dbinkAndToner.InkAndToners
Join dtIl In dbinkAndToner.ItemsLists On dtIt.ItemID Equals dtIl.ItemID
Where dtIl.IsAvailable = True
Select New With {
.Alpha = ((dtIt.Manufacturer).Substring(0, 1))
}
Distinct
query = From dtIt In query
Order By dtIt.Alpha
Dim dtManufacturer As DataTable = csLINQOperations.LINQToDataTable(query)
Return dtManufacturer