I'm trying to a LINQ query, and I have been stumped for some time. I tried looking up the documentation, and around here, but I can't quite seem to find enough pieces to make the whole thing.
If I were to be writing this in SQL, the query would be
SELECT *
FROM (Person JOIN Event ON Person.ID = Event.PersonID) as t
Where (Event.Type = "Invitation") AND !Exists(SELECT *
FROM Event
WHERE Event.Type = "Something"
AND Event.Conference = "someString"
AND t.ID = Event.PersonID)
Any input would be greatly appreciated, even if you only have a solution for part.
Your Event table appears to have a foreign key to Person. This seems unusual as it would imply that an Event can only have one person. I'm going to assume that your Event table is the many-many table in this model. Assuming you have an association between People and Events (PeopleEvents?), you should be able to do this with something like the following (using !Any in place of !Exists):
from person in People
from event in person.Events
where event.Type == "Invitation" &&
!person.Events.Any(event => event.Type == "Something" && event.Conference == "someString")
select new {person, event}
(note, you may want to project into some other structure here rather than projecting the select many I'm showing here.) If we had more information about your model or what you are trying to accomplish, we might be more help.
Related
I've got a few tables, Deployment, Deployment_Report and Workflow. In the event that the deployment is being reviewed they join together so you can see all details in the report. If a revision is going out, the new workflow doesn't exist yet new workflow is going into place so I'd like the values to return null as the revision doesn't exist yet.
Complications aside, this is a sample of the SQL that I'd like to have run:
DECLARE #WorkflowID int
SET #WorkflowID = 399 -- Set to -1 if new
SELECT *
FROM Deployment d
LEFT JOIN Deployment_Report r
ON d.FSJ_Deployment_ID = r.FSJ_Deployment_ID
AND r.Workflow_ID = #WorkflowID
WHERE d.FSJ_Deployment_ID = 339
The above in SQL works great and returns the full record if viewing an active workflow, or the left side of the record with empty fields for revision details which haven't been supplied in the event that a new report is being generated.
Using various samples around S.O. I've produced some Entity to SQL based on a few multiple on statements but I feel like I'm missing something fundamental to make this work:
int Workflow_ID = 399 // or -1 if new, just like the above example
from d in context.Deployments
join r in context.Deployment_Reports.DefaultIfEmpty()
on
new { d.Deployment_ID, Workflow_ID }
equals
new { r.Deployment_ID, r.Workflow_ID }
where d.FSJ_Deployment_ID == fsj_deployment_id
select new
{
...
}
Is the SQL query above possible to create using LINQ to Entities without employing Entity SQL? This is the first time I've needed to create such a join since it's very confusing to look at but in the report it's the only way to do it right since it should only return one record at all times.
The workflow ID is a value passed in to the call to retrieve the data source so in the outgoing query it would be considered a static value (for lack of better terminology on my part)
First of all don't kill yourself on learning the intricacies of EF as there are a LOT of things to learn about it. Unfortunately our deadlines don't like the learning curve!
Here's examples to learn over time:
http://msdn.microsoft.com/en-us/library/bb397895.aspx
In the mean time I've found this very nice workaround using EF for this kind of thing:
var query = "SELECT * Deployment d JOIN Deployment_Report r d.FSJ_Deployment_ID = r.Workflow_ID = #WorkflowID d.FSJ_Deployment_ID = 339"
var parm = new SqlParameter(parameterName="WorkFlowID" value = myvalue);
using (var db = new MyEntities()){
db.Database.SqlQuery<MyReturnType>(query, parm.ToArray());
}
All you have to do is create a model for what you want SQL to return and it will fill in all the values you want. The values you are after are all the fields that are returned by the "Select *"...
There's even a really cool way to get EF to help you. First find the table with the most fields, and get EF to generated the model for you. Then you can write another class that inherits from that class adding in the other fields you want. SQL is able to find all fields added regardless of class hierarchy. It makes your job simple.
Warning, make sure your filed names in the class are exactly the same (case sensitive) as those in the database. The goal is to make a super class model that contains all the fields of all the join activity. SQL just knows how to put them into that resultant class giving you strong typing ability and even more important use-ability with LINQ
You can even use dataannotations in the Super Class Model for displaying other names you prefer to the User, this is a super nice way to keep the table field names but show the user something more user friendly.
schedule = Session.select()
.join(Activity).join(Course)
.join(StuCouRel)
.join(Student)
.where(Student.id == current_user.id)
.join(StuActIgnore).where(Activity.id != StuActIgnore.activity)
Now, if StuActIgnore.activity has, say, three rows in this query, then it will have each session that 'gets through' output three times. It will compare each Session to every row in StuActIgnore.activity. I know what's going wrong; I just don't know how to fix it.
I want something like this:
schedule = Session.select()
.join(Activity).join(Course).join(StuCouRel).join(Student)
.where(Student.id == current_user.id)
.join(StuActIgnore)
.where(Activity.id not in StuActIgnore.activity)
that is; if Activity.id does not match for any StuActIgnore row, then the Session is added to the query. The code I wrote does not work because a ForeignKeyField is not iterable.
EDIT: I tried fixing it as follows:
schedule = Session.select()
.join(Activity)
.join(Course)
.join(StuCouRel)
.join(Student)
.where(Student.id == current_user.id)
.join(StuActIgnore)
.where(Activity not in current_user.ignoredactivities)
because this related_name ("ignoredactivities") is iterable, but this doesn't seem to work either.
EDIT2: I made it work by adding a separate for-loop. It works, but it's neither efficient nor elegant:
ignored = Activity.select().join(StuActIgnore).where(StuActIgnore.student == current_user.id)
for element in schedule:
if element.activity not in ignored:
classes.append(element)
Is there a more elegant way of doing the same thing?
I have rails controller coding as below:
#checked_contact_ids = #list.contacts.all(
:conditions => {
"contacts_lists.contact_id" => #list.contacts.map(&:id),
"contacts_lists.is_checked" => true
}
).map(&:id)
its equivalent to sql
SELECT *
FROM "contacts"
INNER JOIN "contacts_lists" ON "contacts".id = "contacts_lists".contact_id
WHERE ("contacts_lists".list_id = 67494 )
This above query takes more time to run, I want another way to run the same query with minimum time.
Is anyone knows please notice me Or is it possible? or is the above query enough for give output?
I am waiting information...................
I think the main problem with your original AR query is that it isn't doing any joins at all; you pull a bunch of objects out of the database via #list.contacts and then throw most of that work away to get just the IDs.
A first step would be to replace the "contacts_lists.contact_id" => #list.contacts.map(&:id) with a :joins => 'contact_lists' but you'd still be pulling a bunch of stuff out of the database, instantiating a bunch of objects, and then throwing it all away with the .map(&:id) to get just ID numbers.
You know SQL already so I'd probably go straight to SQL via a convenience method on your List model (or whatever #list is), something like this:
def checked_contact_ids
connection.execute(%Q{
SELECT contacts.id
FROM contacts
INNER JOIN contacts_lists ON contacts.id = contacts_lists.contact_id
WHERE contacts_lists.list_id = #{self.id}
AND contacts_lists.is_checked = 't'
}).map { |r| r['id'] }
end
And then, in your controller:
#checked_contact_ids = #list.checked_contact_ids
If that isn't fast enough then review your indexes on the contacts_lists table.
There's no good reason not go straight to SQL when you know exactly what data you need and you need it fast; just keep the SQL isolated inside your models and you shouldn't have any problems.
I have tried to find an answer to this, but could not find one in google. Probably not searching the correct terms, so thought I would ask here.
The following returns all my contacts, not the ones that equal the adjusterType sent in.
var contacts = from c in session.Linq<Contact>() select c;
contacts.Where(c => c.ContactAdjuster.AdjusterType == adjusterType);
The following does return the expected results. It does return only the contacts that meet the adjusterType. I believe it is my lack of understanding of LINQ.
var contacts = from c in session.Linq<Contact>() select c;
contacts = contacts.Where(c => c.ContactAdjuster.AdjusterType == adjusterType);
Thanks in advance.
the Where clause returns an IEnumerable in your case an IEnumerable. This is the standard LiNQ and C# behavior. Instead of modifying your collection it is returning a new collection based on your where clause.
I suppose NHibernate LiNQ should mimic this.
CatZ is absolutely right, you are not modifying the "contacts" collection/enumerable you are creating a new based on the existing, which is why your second statement works.
But instead of just repeating CatZ statement, here is a little add-on:
You can write this in one statement though
var contacts =
from c in session.Linq<Contact>()
where c.ContactAdjuster.AdjusterType == adjusterType
select c;
Or simply
var contacts = session.Linq<Contact>().Where(c => c.ContactAdjuster.AdjusterType == adjusterType);
I am having a few issues with trying to live in a subsonic world and being a subsonic girl when it comes to subsonic expressions....
after reading Subsonic Query (ConditionA OR ConditionB) AND ConditionC it would appear i am not the only one with this sort of issue but hopefully someone (the almighty rob??) can answer this.
i am attempting to create an expression in my query based on a looping condition. what i want to achieve (in pseudo code) is something like this:
objQuery.andexpressionstart();
foreach (condition in conditions){
if (condition){
objQuery.and(conditionColumn).isequalto(X);
}
}
objQuery.expressionstop();
my main issue is that each condition that is inside the expression is a different column - otherwise i could just use .In() . i also have extra search criteria (read a fair bit) outside so it can't be outside an expression.
i REALLY don't want to leave the warm coseyness of the strongly-typed-subsonic womb however i think in this instance i might have too... if i DO have to is there a way to add to a subsonic query with a hand typed condition so i don't have to change all the other code in the query (alot of business logic living in subsonic land right now)
As always, thanks for any help
cheers
I haven't the time to test this right now, but I think if you do something like the following should work:
bool isFirstCondition = true;
foreach (condition in conditions){
if (condition)
{
if(isFirstCondition)
{
objQuery.AndExpression(conditionColumn).isequalto(X);
isFirstCondition = false;
}
else
{
objQuery.and(conditionColumn).isequalto(X);
}
}
}
Make sure all your other conditions have been added prior to the loop.