I've got a problem with Linq in VB.NET.
I've created a .dbml file from my db, and everything looks good - relation "arrows" between tables are visible, etc.
But when I want to use simple query (taken from 101 Linq Samples by MS):
Dim q = From h In dc.Hours, w In h.WorkType
I receive an error:
Expression of type 'INTegrity.WorkType' is not queryable. Make sure you are not missing an assembly reference and/or namespace import for the LINQ provider.
h.Worktype is visible in Intellisense...
I can manually join in the Linq query, but shouldn't the relations be automatic?
The full query that works, but using "manual joins" looks like this:
Dim q1 = From g In dc1.Hours _
Join pr In dc1.WorkType On g.WorkTypeId Equals pr.WorkTypeId _
Where g.WorkerId = workerid _
Select New With {g.EntryId, g.Date, pr.WorkTypeDesc, g.Minutes}
Worktype table has 1 to many relationship with Hours table (as you can see on the WorkTypeId column)
I don't speak LINQ in VB, so I'll try to adapt to C#
From h In dc.Hours, w In h.WorkType
from h in dc.Hours
from w in h.WorkType
.....
This implies that WorkType is a collection, which it's name does not suggest. I think you want something closer to
from h in dc.Hours
let w = h.WorkType
....
Of course, none of these will do anything without the parts in the "....". If you show us what you want to do there, we could probably fix it for you.
UPDATE#1:
Trying to piece together what you are doing, let's guess that Hours & WorkType are tables with a one-to-many relationship (WorkType on the "one" side), hence every Hours record matchs one WorkType record. In that case, Linq-to-SQL will automatically generate a scalar WorkType property in Hours. You don't need the "from ... in " to access it. It's just a property, use it directly where you need it.
UPDATE#2: (From comments)
I think this should work:
Dim q1 =
From g In dc1.Hours
Where g.WorkerId = workerid
Select New With {g.EntryId, g.Date, g.WorkType.WorkTypeDesc, g.Minutes}
Related
So I have an Entity Framework 5 model that includes a many-to-many relationship.
CategoryValues --< CourseCategoryValues >-- Courses
I have a LINQ query that selects every Course in the database. I would really like to modify it to only select Courses that belong to a specific CategoryValue. My attempt thus far has failed?
Can anyone help me figure this out?
This is what I have tried:
Using database As SiteDataContext = New SiteDataContext
database.Configuration.ProxyCreationEnabled = False
database.Courses.Include("Classes")
database.Courses.Include("CourseCategoryValues")
query = (From c In database.Courses Select c Order By c.Name).Where(
Function(c) 0 < c.Classes.Where(Function([class]) [class].Status.ToLower = "open").Count
).Include(Function(r) r.Classes).Include(Function(r) r.CourseCategoryValues)
' Here is where I am trying to narrow down the query results
If (pid.HasValue) AndAlso (0 <> pid.Value) Then
query.Where(Function(c) c.CourseCategoryValues.Any(Function(v) v.CategoryValue.CategoryValueID = pid))
End If
model.PageData = query.ToList
End Using
I think you are only missing the assignment of the filter to the query variable. Where returns a new queryable, it doesn't modify the queryable you apply the Where to. So, you would need:
query = query.Where(...)
The Where expression itself looks correct to me.
I have a query in the DB:
SELECT GreenInventoryBlendGradeID,bgx.blendgradeid,
bgX.GreenBlendGradeTypeID,[Description]
FROM [GreenInventory] gi
INNER JOIN [GreenInventoryBlendGradeXref] bgX
ON bgX.[GreenInventoryID] = gi.[GreenInventoryID]
INNER JOIN [BlendGrade] bg
ON bg.[BlendGradeID]=bgx.[BlendGradeID]
That returns 3 records:
TypeID Desc
1 XR
2 XR
1 XF2
The LINQ:
var GreenInventory = (from g in Session.GreenInventory
.Include("GreenInventoryBlendGradeXref")
.Include("GreenInventoryBlendGradeXref.BlendGrade")
.Include("GreenInventoryBlendGradeXref.GreenBlendGradeType")
.Include("GreenInventoryWeightXref")
.Where(x => x.GreenInventoryID == id && x.GreenInventoryBlendGradeXref.Any(bg=>bg.GreenBlendGradeTypeID > 0) )
select g);
I have tried different Where clauses including the simple - (x => x.GreenInventoryID == id)
but always have only the first 2 records returned.
Any Ideas?
If I try the following:
var GreenInventory = (from gi in Session.GreenInventory.Where(y => y.GreenInventoryID == id)
join bgX in Session.GreenInventoryBlendGradeXref.DefaultIfEmpty() on gi.GreenInventoryID equals bgX.GreenInventoryID
join bg in Session.BlendGrade.DefaultIfEmpty() on bgX.BlendGradeID equals g.BlendGradeID
select new { GreenInventory = gi, GreenInventoryBlendGradeXref = bgX, BlendGrade = bg });
I Get back 3 of each objects and the correct information is in the BlendGrade objects. It looks like the 3 GreenInventory objects are the same. They each include 2 of the GreenInventoryBlendGradeXref objects which show the the same 2 records as before.
So I not clear on what the original problem was. Also dont know if this is the best way to resolve it.
Thanks for the answers. If anyone has a further thoughts please let us know.
Based on the few details you present, I would assume that you are missing a join. I have no experience with EntityFramework (I assume that you use this ORM), but as far as I know, the ".Include" tries to ensure that the set of root entities will not change and will not contain duplicates.
Your manually created query seems to indicate that there is at least one 1:n relationship in the model. The result you get from LINQ show that only distinct GreenInventory entities are returned.
Therefore you need to adjust your query and explicitly declare that you want all results (and not only distinct root entities) - I would assume that with an explicit join EntityFramework will yield all expected results - or you need to adjust your mapping.
The first place I'd look in would be your model and joins you have defined between the entities. You might also want to check your generated SQL statement:
Trace.WriteLine(GreenInventory.Provider.ToString())
or use Visual Studio IntelliTrace to investigate what was sent to the database.
First of all, please forgive me for my vocabulary is a little limited with NHibernate so I might call something the wrong thing...here is my question:
Result I am looking for is a count of distinct students for a course. I have three classes:
Courses, Students, CourseDates.
Courses contains a HasMany relationship with CourseDates.
CourseDates is a collection of dates on which each class has occurred and contains a HasAndBelongsToMany relationship with the Students class.
What I need to do is a get a distinct count of the Students from all the dates a course has occurred. Here is an example of a SQL statement that I want to replicate. The result is a number (long). This specific example produces the result: 5
SELECT COUNT(DISTINCT dbo.Literacy_Course_DatesStudents.IDStudent) AS StudentCount FROM
Literacy_Course_DatesStudents INNER JOIN Literacy_Course_Dates ON Literacy_Course_DatesStudents.IDDate = Literacy_Course_Dates.IDDate WHERE (Literacy_Course_Dates.IDCourse = 28)
Below is the query written from within a new class that I created specifically for this report...but I keep getting an error: Exception of type 'Antlr.Runtime.MissingTokenException' was thrown. Usually I thought this error was thrown when I didn't have CourseEnrolledCount class imported into the other classes but I have done that.
Dim q As Castle.ActiveRecord.Queries.SimpleQuery(Of CourseEnrolledCount)
q = New Castle.ActiveRecord.Queries.SimpleQuery(Of CourseEnrolledCount)(GetType(Literacy.Courses.CourseDates), "select new CourseEnrolledCount(Count(Distinct o.IDStudent in elements(t.Students) as o)) from CourseDates t Where t.Course.IDCourse = :courseid")
Let me know if I need to provide additional information. I hope I am being clear in my question. Thank you in advance for your time.
Here is a HQL query that does what you want:
select count(disctinct student.id) from Course course
inner join course.courseDates courseDate
inner join courseDate.students student
where course.id = :courseId
I'll let you substitute the real names of the associations.
You could even make it shorter (and more similar to your SQL query) by avoiding the join on the course:
select count(disctinct student.id) from CourseDate courseDate
inner join courseDate.students student
where courseDate.course.id = :courseId
I have a the following setup
m_handsets = From p In RL.App.TComEntities.tblTelephoneNumbers _
Where p.companyId = m_CompanyID _
Select p
m_handsets = DirectCast(m_handsets, ObjectQuery(Of RL.TelephoneNumbers)).Include("tblCalls")
where m_handsets is defined as
Private m_handsets As IQueryable(Of RL.tblTelephoneNumbers)
which works as expected however what I want to do know is query the Navigation property (tblCalls) so I can do something like the following
From p In m_handsets.tblCalls
Where m_handsets.tblCalls.price > 100
but I have no idea of the proper syntax, can anyone help?
EDIT:
I think the complexity comes here because in this instance I could have 5 tblTelephoneNumbers in m_handsets and then x amount of calls for that particular telephone number. I am interested in the tblCalls for each but I would like to filter them all for each tblTelehoneNumber.
Entity Diagram which (hopefully) should illustrate further
So I currently know all the handsets that are associated with the company I am interested in. I can also see the calls loaded as a navigation property in debug mode, but I want to say is take this filter (in this example price>100 and apply it to all handsets->calls
If understand your question correctly, then you have 2 solutions to accomplish this:
In both solution you'll see that I remove the Include method since Include does NOT allow you to filter the related data.
1. Filtered Projection (Returns Anonaymous Type):
Dim results = From p In RL.App.TComEntities.tblTelephoneNumbers _
Where p.companyId = m_CompanyID _
Select New With {.Handsets = p, _
.tblCalls = p.tblCalls.Where(Function(t) t.price > 100)}
However, it might not be desirable in all situations as it gives a collection of anonymous type objects.
2. Two Tracked Queries (Returns EntityObjects):
This one gives you a collection of your entityobject tblTelephoneNumbers:
Dim m_handsets = (From p In RL.App.TComEntities.tblTelephoneNumbers _
Where p.companyId = m_CompanyID Select p).ToList()
Dim m_tblCalls = (From t In RL.App.TComEntities.tblCalls _
Where t.price > 100 Select t).ToList();
ForEach(Dim t In m_tblCalls)
m_handsets.Single(Function(h) h.ID = t.tblTelephoneNumberID).tblCalls.Add(t)
End ForEach
3. Leveraging Attach Method (Returns EntityObjects):
The last and probably the best and most elegant solution is to use EntityCollection.Attach Method along with EntityCollection.CreateSourceQuery:
foreach (var tel in m_handsets) {
IQueryable<tblCalls> sourceQuery = tel.tblCalls.CreateSourceQuery()
.Where(c => c.price > 100);
tel.tblCalls.Attach(sourceQuery);
}
Sorry for any VB syntax mistake, I wrote them all off the top of my head.
I'm looking to create a Left outer join Nhibernate query with multiple on statements akin to this:
SELECT
*
FROM [Database].[dbo].[Posts] p
LEFT JOIN
[Database].[dbo].[PostInteractions] i
ON
p.PostId = i.PostID_TargetPost And i.UserID_ActingUser = 202
I've been fooling around with the critera and aliases, but I haven't had any luck figuring out how do to this. Any suggestions?
I actually figured it out. You need to do a check for null
.CreateCriteria("Interactions", "i", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Expression.Or(Expression.Eq("i.ActingUser", user), Expression.IsNull("i.ActingUser")))
this creates a left join on targetpost id and then eliminates all non null/non user interactions.
I spent a long while checking all kinds of posts that did not do what I needed and your post is the closest to what I was looking for.
From my tests (with nHibernate 3) your query is not correct. Actually your criteria looks more like this in SQL :
SELECT *
FROM [Posts] p
LEFT JOIN [PostInteractions] i
ON p.PostId = i.PostID_TargetPost
WHERE (i.UserID_ActingUser = 202 OR i.UserID_ActingUser IS NULL)
Which returns posts/interactions only when the interaction's ActingUser is 202 or that no interaction exists for the post.
After lot more tests I finally figured it out...
Try this (vb.net) :
session.CreateCriteria(Of Posts)("p") _
.CreateCriteria("Interactions", "i", _
NHibernate.SqlCommand.JoinType.LeftOuterJoin, _
Expression.Eq("i.ActingUser", user))
There's an overload to the CreateCriteria function using a "withClause". That worked perferctly for me and I believe that it's what you're looking for too.
I know the topic's pretty old but if it can help anyone else....
Also, for great examples on nHibernate queries (it was a huge help for me): http://ayende.com/blog/4023/nhibernate-queries-examples
Have fun!