I am attempting to query for an ID from table that needs to be joined with a negative result. In other words choose all the ScacIDs where that ScacID is not present in the joined table ScacSetup. This query returns no result.
var tasksNotAssociated = from scac in db.Scacs
where !db.ScacSetupTasks.Any(s => s.ScacTaskID == taskID)
group scac by scac.ScacCode into scacNotAssociated
select scacNotAssociated.FirstOrDefault();
Great and yes my solution was to use the left join that was provided by my navigation property; ScacSetupTasks. Guess I should have posted my navigation property and tagged with Entity Framework. OK, here is what I found to work and is essentially a left join where leftside == null as suggested by MarcinJeraszek, thanks buddy.
var scacsNotAssociated = db.Scacs.Where(s => s.ScacSetupTasks.Count(sst => sst.ScacTaskID == taskID) == 0);
Related
I'm trying to convert this SQL query to LINQ
select * from fichepfe where valid = 1 and id_fiche in ( select fiche_id from enseignant_fiche where id_ens = '*variable*');
This query can return multiple rows.
This is what I tried but I keep getting this error
Operator '==' cannot be applied to operands of type 'method group' and 'IQueryable'
What I tried:
var fiches = (from fiche in _context.Fichepfes where fiche.Valid == true && fiche.IdFiche ==
(from fens in _context.enseignant_fiche where IdEns == *variable*
select fens.ficheId )
select fiche ).ToList();
Thanks in advance.
This should work:
var fiches =
(from fiche in _context.Fichepfes where
fiche.Valid == true &&
_context.enseignant_fiche.Any(fens => fens.IdEns == *variable* && fens.ficheId == fiche.IdFiche)
).ToList();
However this may cause part of the query to be executed by the client, since LINQ-to-SQL may be unable to convert the .Any() call to a raw query.
A better way would be to use a join:
var fiches =
(from fens in _context.enseignant_fiche where fens.IdEns == ens
join fiche in _context.Fichepfes on fens.ficheId equals fiche.IdFiche
where fiche.Valid
select fiche.IdFiche).ToList();
The join can be done the other way around, too, but it's around 5 to 6 times slower on my computer.
var fiches =
(from fiche in _context.Fichepfes where fiche.Valid
join fens in _context.enseignant_fiche on fiche.IdFiche equals fens.ficheId
where fens.IdEns == ens
select fiche.IdFiche).ToList();
So you have a table of Fiches (FichePfes), and a table of EnseignantFiches (enseignant_fiche).
There seems to be a relation between Fiches and EnseignantFiches: every Fiche has (owns?) exactly one EnseignantFiche, namely the EnseignantFichethat the foreign keyIdFiche` refers to.
Furthermore, every Fiche has a Boolean property Valid; every EnseignantFiche has a (string?) property IdEns.
Requirement: Give me all Valid Fiches, that owns an EnseignantFiche with a value of IdEns that equals "variable"
var validFiches = dbContext.Fiches.Where(fiche => fiche.Valid);
var variableEnseignantFiches = dbContext.EnseignantFiches
.Where(enseignantFiche => enseignantFiche.IdEns == "*variable*";
var requestedFiches = validFiches.Join(
variableEnseignantFiches,
fiche => validFiche.IdFiche, // from every Fiche take the foreign key
enseignantFiche => enseignantFiche.IdFiche, // from every EnseignatFiche take primary key
(fiche, enseignantFiche) => new // when they match, make one new object
{
// Select the fiche properties that yo plan to use
FicheId = fiche.Id,
FicheName = fiche.Name,
...
// Select the EnseignantFiche properties that you plan to use:
EnseignantName = enseignantFiche.Name,
...
});
In words:
From the table of Fiches, keep only the Valid ones.
From the table of EnseignantFiches, keep only those with an IdEns equal to "Variable"
Join these two tables on Primary key equals Foreign key, and Select the properties that you plan to use.
Of course you can do this in one big LINQ statement. Because the query is not executed yet, this won't enhance process speed. It will surely deteriorate readability, testability and reusability.
According to this StackOverflow answer:
Linq to Entities - how to filter on child entities
you should be able to filter down the list of related entities in Entity Framework by utilizing a projection, like I've done here:
Company company = _context.Company
.Where(g => g.CompanyId == id)
.Select(comp => new
{
group = comp,
operators = comp.Operator,
formFamilies = comp.FormFamily.Where(ff => ff.IsActive ?? false)
}).AsEnumerable().Select(i => i.group).FirstOrDefault();
To give a quick overview of what I'm trying to obtain here, I'm trying to get a list of all of the active form families associated with this company object, however, whenever I restrict the results in any way, the result set is empty.
If the line were formFamilies = comp.FormFamily then it returns two results, one active one inactive
If the line is formFamilies = comp.FormFamily.Where(ff => true) then it returns nothing
If the line is formFamilies = comp.FormFamily.OrderBy(ff => ff.FormFamilyId) then it returns nothing.
Any sort of modification that I do to comp.FormFamily means the result set returns nothing, I've dug through the deepest sections of SA to try to find a solution, and tried every solution I've found, but nothing seems to cause this list to return anything.
Assuming that Company and FormFamily entities has one to many relationship I would suggest to use a join statement.Something like this should give you what you are looking for.
var company = from c in _context.Company
join f in _context.FormFamily
on c.Id equals f.CompanyId
where c.Id == id
select new Company()
{
Id = c.Id,
operators = c.Operator.ToList(),
formFamilies = c.FormFamily.Where(x=>x.IsActive ==
false).ToList()
} .FirstOrDefault();
Hope this helps.
I didn't quite understand what is your query is supposed to do. But it seems to me that you cannot just call Select method on another Select result method.
Anyway, you could simply use Include methods instead of projecting.
var company = _context.Company
.Where(c => c.Id == id)
.Include(c => c.FormFamily).Where(ff => ff.IsActive ?? false)
.ToList();
Did not test it. To prove it works or not be sure put an entity model in the question. Then I may produce more accurate answer.
I need to write some linq (linq-to-sql) for a search page that allows the user to search for cars and optionally include search criteria for the car's parts. The two tables are CAR and CAR_PARTS. Here is what I have so far:
var query = db.CAR;
//if the user provides a car name to search by, filter on car name (this works)
if(model.CarName != "")
{
query = from c in query
where c.Name == model.CarName
select c;
}
//if the user provides a car part name to filter on, join the CAR_PART table
if(model.CarPartName != "")
{
query = from c in query
join parts in db.CAR_PARTS on c.ID equals parts.CarID
where parts.PartName == model.CarPartName
select c;
}
//if the user provides a car part code to filter on, join the CAR_PART table
if(model.CarPartCode != "")
{
query = from c in query
join parts in db.CAR_PARTS on c.ID equals parts.CarID
where parts.PartCode == model.CarPartCode
select c;
}
If the user decides they want to search on both CarPartName and CarPartCode, this logic would result in the CAR_PART table being joined twice. This feels wrong to me, but is this the correct way to handle this?
How would you write this?
It's legal to do so, but whether it makes sense, depends on your datamodel and your desired outcome.
Generally your code does the following if partname and partcode are defined
Join the cars table with the parts table with partname as join condition
Join the result of the first join again with the parts table with partcode as join condition.
Thus, this is equal to a join with join condition car.partname = part.name and car.partcode = part.code. I don't know, whether this is your desired behaviour or not.
There are some cases to distinguish
Joining with AND condition
CASE 1.1: name and code of a part are keys in the parts table
In this case for each name and code are each unique in the parts table, thus for each name there is exactly one code. The double join is not necessary, and may even lead to wrong results, because
if selected name and code identify the same part, it's the first join will already get the desired results
if name and code identifiy different parts, your result will be empty because the condition cannot be fullfilled.
In that situation I would suggest to write is as follows
if (!string.IsNullOrEmpty(model.CarPartName)){
// your join on partname
} else if (!string.IsNullOrEmpty(model.CarPartCode)) {
// your join on partcode
}
CASE 1.2: name and code of a part are NOT keys in the parts table
In this case, neither name nor code may be unique, and for one name there may be different codes and vice versa. Here the double join is necessary and will only return results containing parts which match both, name and code
Joining with OR condition
If on the other hand you want your join condition to be like car.partname = part.name and car.partcode = part.code you have to consider the following cases
CASE 2.1 name and code are keys
Here applies the same as above in case 1.1
CASE 2.2 name and code are NOT keys
Here you can't use the stepwise approach, because the result of the first join will only contain cars, where the name matches. There may be parts where only the code condition matches, but they can never be included in the final result, if they are not contained in the result of the first match. So in this case, you will have to define your query something like this
if (!string.IsNullOrEmpty(model.CarPartName) && !string.IsNullOrEmpty(model.CarPartCode)) {
query = from c in query
join parts in db.CAR_PARTS on c.ID equals parts.CarID
where parts.PartName == model.CarPartName || parts.PartCode == model.CarPartCode
select c;
} else if (!string.IsNullOrEmpty(model.CarPartName)) {
query = from c in query
join parts in db.CAR_PARTS on c.ID equals parts.CarID
where parts.PartName == model.CarPartName
select c;
} else if (!string.IsNullOrEmpty(model.CarPartCode)) {
query = from c in query
join parts in db.CAR_PARTS on c.ID equals parts.CarID
where parts.PartCode == model.CarPartCode
select c;
}
What is wrong in there is actually with proper relations you don't need the join at all. Add that the behavior of LinqToSQL you can write that as:
var query = db.CAR
.Where( c =>
( string.IsNullOrEmpty(model.CarName)
|| c.Name == model.CarName ) &&
( string.IsNullOrEmpty(model.CarPartName)
|| c.Parts.Any( p => p.PartName == model.CarPartName )) &&
( string.IsNullOrEmpty(model.CarPartCode)
|| c.Parts.Any( p => p.PartCode == model.CarPartCode )));
Yours would work provided query is IQueryable (db.CAR.AsQueryable()). The two Linq approaches are similar but not the same. Depending on your real necessity yours might be the correct one or the wrong one. Yours would produce two inner joins, while this one simply create 2 exists check. Assume you have:
Car, Id:5, Name: Volvo
And parts like:
CarID:5, PartName:HeadLights, PartCode:1 ... other details
CarID:5, PartName:HeadLights, PartCode:2 ... other details
CarID:5, PartName:HeadLights, PartCode:3 ... other details
If user asks with model.CarName = "Volvo" and model.PartName = "HeadLights", you would get back the same Volvo 3 times. In second approach, you get back a single Volvo.
HTH
I feel more comfortable with fluent syntax, but I'm sure something similar to the following will work for you. I would check the fields in your model as part of a Select statement and then conditionally join using one field or the other. If neither are set, leave it null.
var query = db.CAR;
if (!string.IsNullOrWhitespace(model.CarName))
{
query = query.Where(car => car.Name == model.CarName);
}
var items = query.Select(car => new
{
Car = car, // maybe better to split this up into different fields, but I don't know what the car object looks like
// I assume your Car entity model has a navigation property to parts:
CarPart = !string.IsNullOrWhitespace(model.CarPartName)
? car.Parts.FirstOrDefault(part => part.PartName == model.CarPartName)
: !string.IsNullOrWhitespace(model.CarPartCode)
? car.Parts.FirstOrDefault(part => part.PartCode == model.CarPartCode)
: null
})
.ToList();
This does mean that the Code will be ignored if the Name is filled in. Reverse it if it needs to be the other way around. Or if you want to use both fields, you can put the string null checks in the Where clause.
I have two tables:
Team: teamId, teamName
Player: playerId, teamId, playerName
I want to get the teamName through playerName. I wrote two querys, one of them doesn't work.
var query = from t in dc.Teams
where t.teamId == ((from p in dc.Players
where p.playerName == "kobe"
select p.teamId).SingleOrDefault())
select t.teamName; //Doesn't work
var query = from t in dc.Teams
join p in dc.Players
on t.teamId equals p.teamId
where p.playerName == "kobe"
select t.teamName; //Works
Anyone can tell me why the first query couldn't work?
Both queries should yield the same result if there are one or zero players named "kobe". If there are more than one players named "kobe", the first query won't return anything because its subquery uses SingleOrDefault, which returns the default value if the collection doesn't contain exactly one value, while the second query will return the teamName for each player named "kobe".
Risky Martin already mentioned the reasons but in addition to this,
You can use FirstOrDefault instead of SingleOrDefault. By using FirstOrDefault, your query can return any amount of results but you state that you only want the first result.
var query = from t in dc.Teams
where t.teamId == ((from p in dc.Players
where p.playerName == "kobe"
select p.teamId).FirstOrDefault())
select t.teamName; //Now it works
I have several tables that are properly linked and mapped through FKs / link tables.
ie: link_table -> 1 to many relationship to table_one and table_two -> many to many relationship to table_three
var results = db.link_table.Where(l => l.table_one.RandomProperty == "value");
The above obviously works but I want to be able to make a select like this:
var results = db.link_table.Where(l => l.table_one.RandomProperty == "value" && l.table_two.table_three.RandomProperty == "anothervalue");
This fails because it seems not possible to access the properties that belong to table_three. The SQL query I would like should resemble something like this (the WHERE part is the most important):
SELECT * FROM link_table
LEFT JOIN table_one ON table_one.assoc = link_table.assoc
LEFT JOIN table_two ON table_two.assoc = link_table.assoc
LEFT JOIN table_three ON table_two.assoc = table_three.assoc
WHERE table_one.RandomProperty = "value" AND table_three.RandomProperty = "AnotherValue"
How would I be able to access the "RandomProperty" of table_three through the relational mapping of Linq2Entities? Is it even possible in one single line of code and thus getting the result I want in one automatically generated SQL query?
First declare all your FK properties as virtual in all model classes.
And then use this code:-
var results = db.link_table.Where(l => l.table_one.RandomProperty == "value" && l.table_two.table_three.RandomProperty == "value").FirstOrDefault();
The in-depth answer is given to this question: linq to entities, a where in where clause? (inner where). It involves using the .Any() command to search through the related many-to-many table data.
i.e.:
var results = db.link_table.Where(l => l.table_one.RandomProperty == "value" && l.table_two.table_three.Any(t => t.RandomProperty == "value"));