SQL "not in" syntax and nested SELECT in Entity Framework - sql

I recently used Entity Framework. For elementary CRUD operations, I have no problems, but for more complicated queries, I do not know how to do these.
For example: how to write a nested select? How to use the NOT IN operator?
The query that I want to write is:
SELECT *
FROM course
WHERE idCourse NOT IN (SELECT idCourse
FROM reservation
WHERE idStudent = 'value');
I do not know where to start. Could you please give me some advice?

If I do not misunderstood your question, you want to know how to write the question's query as LINQ-to-Entity query.
Examples could be:
var courses = context.Courses
.Where(c => c.Reservations.All(r => r.idStudent != "value"))
.Select(c => c);
// with eager loading
var courses = (from c in context.Courses.Include(c => c.Reservations)
where c.Reservations.All(r => r.idStudent != "value")
select c).ToArray();
var courses = (from c in context.Courses
join r in context.Reservations on c.idCourse equals r.idCourse
where r => r.idStudent != "value"
select c).ToArray();
The Contains() is equivalent to EXIST IN in a query. Well, 1st and 2nd nearly the same. Only difference is the Include method to show how you could eager load data.
In the 3rd query I use the join key word to do a join operation - equivalent to an INNER JOIN. The result will contain only records where a relation between a course and a reservation exists and the searched student ID is referenced in the reservation.
If you should not use LINQ for your querys, you should take a look. It's a perfect way to decouple your data access layer from persistence layer and you could test all your queries in code too.
Here you could get a very good entry into the subject.
EDIT:
Modified example code to fit NOT IN.

If you are having trouble executing complex queries with LINQ, you can also execute raw SQL queries. They are easy and faster than linq queries.
Here is an example in c#
var list = dc.Database.SqlQuery<YourCourceClass>(#"SELECT *
FROM course
WHERE idCourse NOT IN(SELECT idCourse
FROM reservation
WHERE idStudent = 'value');").ToList();

Related

EF Core The LINQ expression 'DbSet() could not be translated

What am I missing here?
IQueryable<IsActiveCustomerProviderRefDto> search =
from customerProviderRef in _database.CustomerProviderRef
join customerTrade in _database.CustomerTrade on customerProviderRef.ExternalRefId equals customerTrade.CustomerProviderRef into ctJoin
from customerTradeJoin in ctJoin.DefaultIfEmpty()
select new IsActiveCustomerProviderRefDto
{
CustomerProviderRef = customerProviderRef.ExternalRefId
};
search = search.Where(e => e.CustomerId.Equals(find.customerProviderRef.CustomerId));
return search.FirstOrDefault();
Generates the following error:
Description:The LINQ expression 'DbSet() .Where(c => new IsActiveCustomerProviderRefDto{ CustomerProviderRef = c.ExternalRefId } .CustomerId.Equals("1014706150563885056"))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.(Source: Microsoft.EntityFrameworkCore)
I've tried replacing the FirstOrDefault() call with ToList(), etc but makes no difference.
I'm not entirely sure if my query is spot on either, so I'll provide a SQL version of the query I was attempting to achieve (LINQ is not my specialty)...
SELECT *
FROM CustomerProviderRef [R]
LEFT OUTER JOIN [CustomerTrade] [T]
ON [R].[ExternalRefId] = [T].[CustomerProviderRef]
WHERE
[T].[Id] IS NULL -- essentially where the left outer join fails.
AND
[R].[CustomerId] = #CustomerId
That query looks a bit off, in that you are doing the Where clause after the projection (Select) which I don't believe would compile. The Where clause would expect to be limited to just the values that were selected.
The main issue will be based on what "find" represents in your example. Linking IQueryable queries in EF is possible when EF is happy they can be translated into a single SQL statement, but generally you should avoid it if at all possible. Manually joining DbSets should be reserved for relationships which cannot be represented in the database with actual FK constraints. These are de-normalized relationships, usually hacks to "save space" but result in slow, buggy querying. An example would be something like an Address table with an OwnerType and OwnerId Where OwnerType might be "Customer" or "Business" or several other values, used to define whether the OwnerId should pair to the CustomerId or BusinessId etc. These are slow and buggy because they cannot benefit from FKs or constraints for performance or data integrity.
EF and Linq should not be viewed as a like-for-like replacement for SQL using explicit joins between DbSets. Instead, set up the relationships between entities using Navigation properties with 1-to-many, many-to-one, many-to-many, or 1-to-1 relationships as the database schema structure reflects through FK references. This is what EF is designed to do, to generate SQL to pull back the applicable data from a object model representation of that related data.
based on the query with the relationship (1-to-many between CustomerProviderRef and CustomerTrade on ExternalRefId your Linq query would look more like:
var results = dbContxt.CustomerProviderRef
.Where(x => x.CustomerId == customerId
&& !x.CustomerTrades.Any())
.ToList();
This assumes that there are multiple CustomerProviderRef per CustomerID and you want the ones that have no Trades.
If there is only one expected CustomerProviderRef for a given customer you want to load it and determine if it has any trades:
var customerProviderRef = dbContxt.CustomerProviderRef
.Include(x => x.CustomerTrades)
.Where(x => x.CustomerId == customerId)
.Single();
bool hasTrades = customerProviderRef.CustomerTrades.Any();
This eager loads the trades with the customer, which will fetch any trades when we load this customer's data. EF will work out the joins as neded. From there we can check if the customer has any trades, and add Trades to that CustomerTrades collection and call SaveChanges() on the DbContext and EF will create the row and associate the FKs automatically.

How to Sanitize the SQL in Rails?

I'm new to this RoR world,
I've many SELECT sql queries in my RoR Application, something like this
#replies = Offerreply.find_by_sql ("SELECT * FROM offerreplies WHERE
offer_id="+params [:offer_id])
Some are very simple like above and some are very complex JOINS. most of them are suffering from SQL Injection problem. So., How to Sanitize such SQL statements in RoR?
Edit: How to Handle same in SQL statements which has JOINS and Sub-queries? something like this
#to_be_approved=Beneficiary.find_by_sql("SELECT * FROM beneficiaries WHERE project_id="+params[:id]+" AND NOT id IN (SELECT beneficiaries.id FROM beneficiaries INNER JOIN beneficiaryloans ON beneficiaryloans.beneficiary_id=beneficiaries.id AND beneficiaryloans.hfi_id="+session[:id].to_s+" AND beneficiaries.status_id=4) AND cso_id IN(SELECT user_id FROM user_projects INNER JOIN users ON user_projects.user_id=users.id AND users.user_type_id=2)")
If you're using Rails 3 (as your tag says), you can do it like this.
#replies = Offerreply.where("offer_id = ?", params[:offer_id])
You can find more information at the Rails site.
edit: If you have more than one condition, you can do it like this.
#replies = Offerreply.where("offer_id = ? AND second = ?", params[:offer_id], params[:second])
edit2: And see Micha's answer for multiple joins.
Waynn Lue's answer is fine, but it doesn't show how to query on joined tables. You can do it like this:
Offerreply.joins(:offers).where('offers.id', params[:offer_id])
Or:
Offerreply.joins(:offers).where(:offers => { :id => params[:offer_id] })
Again: if you want to use Rails you really have to learn the Active Record Query Interface. Here's the paragraph on joins. Only use find_by_sql if there is no way of doing it via the "normal" interface.

Rails Inner Join not working but the SQL looks right

So I have 2 tables that are joined by an ID. I'm in rails console and I type:
Programmer.all(:joins=>:assignment)
the sql that is generated is:
SELECT `programmers`.* FROM `programmers` INNER JOIN `assignments` ON `assignments`.`programmer_id` = `programmers`.`id`
The output that is generated is the same as Programmer.all. Why doesn't it include the assignments data?
I believe I majorly overanalyzed your question. If you just want to join any available assignments to programmers, you're looking for:
Programmer.all(:include => :assignment)
Rails is designed so that :joins is used to perform things like sorting and grabbing certain records but still keep the query result to a minimum size -- meaning, :joins never actually includes the results from the joined table in the result.
Now here's my previous answer that assumes you want to perform an INNER JOIN to get only the programmers with assignments, but you also want that data. In that case, you have two options:
#1 - Use :select
Programmer.all(:select => '*', :joins => :assignment)
That will change the SQL to:
SELECT * FROM `programmers` INNER JOIN `assignments` ON `assignments`.`programmer_id` = `programmers`.`id`
Upside: You get the query you want and all the data is somewhere, at least.
Downside: assignments is assigned directly to the Programmer object and not to the proper place at Programmer.assignment.
#2 - Use a combination of :joins and :includes
Programmer.all(:joins => :assignment, :include => :assignment)
Which produces the SQL:
SELECT `programmers`.* FROM `programmers` INNER JOIN `assignments` ON `assignments`.`id` = `programmers`.`assignment_id`
SELECT `assignments`.* FROM `assignments` WHERE (`assignments`.`id` IN (?) )
Upside: All your data is in the right place now. You can refer to programmer.assignment without another query.
Downside: You are running that extra query in a lot of instances. I am fairly sure that Rails tries to optimize this when it needs to, though, and if not, it shouldn't cause you too much overhead.
Simply you can do like
Programmer.includes(:assignment)

How write hibernate criteria for specific SQL?

i need write similar SQL by ICriteria:
Tables:
1Lvl -- 2Lvl -- 3Lvl
SQL:
SELECT * FROM 2Lvl
WHERE 2Lvl.1LvlFK in
(
SELECT 1Lvl.Id
FROM 3Lvl
JOIN 2Lvl ON 3Lvl.2LvlFK = 2Lvl.Id
JOIN 1Lvl ON 2Lvl.1LvlFK = 1Lvl.Id
WHERE 3Lvl.Id = 123
)
I'm sorry for so specific question, but I inherited project with Hibernate from exemployee and I can't still understand hibernate-criteria.
var subQuery = DetachedCriteria.For<Lvl3>("lvl3")
.CreateAlias("Lvl2", "sublvl2", JoinType.InnerJoin)
.CreateAlias("Lvl1", "lvl1", JoinType.InnerJoin)
.Add(Restrictions.EqProperty("sublvl2.Id", "lvl2.Id")
.Add(Restrictions.Eq("lvl3.Id", 123)
.SetProjection(Projections.Property("lvl1.Id"));
Session.CreateCriteria<Lvl2>("lvl2")
.Add(Subqueries.PropertyIn("Lvl1.Id", subQuery));
Should do the trick. I've made assumptions about what your entities are called since 1Lvl, etc.. are not valid C# identifiers. I've also assumed the primary key column of each table was Id. Also a note that this won't produce the exact SQL you're looking for, but it will get you the same result.

How to implement paging in NHibernate with a left join query

I have an NHibernate query that looks like this:
var query = Session.CreateQuery(#"
select o
from Order o
left join o.Products p
where
(o.CompanyId = :companyId) AND
(p.Status = :processing)
order by o.UpdatedOn desc")
.SetParameter("companyId", companyId)
.SetParameter("processing", Status.Processing)
.SetResultTransformer(Transformers.DistinctRootEntity);
var data = query.List<Order>();
I want to implement paging for this query, so I only return x rows instead of the entire result set.
I know about SetMaxResults() and SetFirstResult(), but because of the left join and DistinctRootEntity, that could return less than x Orders.
I tried "select distinct o" as well, but the sql that is generated for that (using the sqlserver 2008 dialect) seems to ignore the distinct for pages after the first one (I think this is the problem).
What is the best way to accomplish this?
In these cases, it's best to do it in two queries instead of one:
Load a page of orders, without joins
Load those orders with their products, using the in operator
There's a slightly more complex example at http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx
Use SetResultTransformer(Transformers.AliasToBean()) and get the data that is not the entity.
The other solution is that you change the query.
As I see you're returning Orders that have products which are processing.
So you could use exists statement. Check nhibernate manual at 13.11. Subqueries.