Linq selecting sub results using select - c#

I'm not sure if I'm looking to use a union here or if this will work.
var users =
db.AspNetUsers.Where(
x => x.AspNetRoles.Select(y => y.Id).Contains("4575754-799a-4bhe-8caf-00002344b7a6"))
.Select(d => d.PatientId);
var patients = from patient in db.Patients
where patient.LastName == lastName && clinicId == patient.ClinicId && users.Contains(patient.Id)
select new
{
patient.LastName,
patient.AspNetUsers.First(d=>d.Email),
patient.Sex
};
This works when I get everything from patients, but when I try to get the email address from the AspNetUsers object I get the message 'can not convert expression type string to return type bool'
When I am in quickwatch, I can see the entire AspNetUsers object returned inside the patient object, but why can't I easily select a single property out of that list?

This expression in LINQ
patient.AspNetUsers.First(d=>d.Email)
means "get me the first AspNetUser whose boolean attribute Email is true". Of course this makes no sense, because Email is a string, not a boolean.
What you need is
patient.AspNetUsers.First().Email

Related

Single database call when passing in a list to LINQ

I get passed in an array of email addresses and for each email address, I need to return numTotal and numActive from members related to that email address.
Traditionally, I would query from the member table and filter where the member's email address exists in the passed in email array. However, this would only return me the list of email address with counts for the emails that exist in the member table. Instead, I need a record for each email address provided regardless if a member has the email address.
My solution is to loop over the email array and then do a subquery. This works, and I'm able to get what I need, but when I profile the calls, I see that EF is running a separate query for each email address/subquery.
var result = (from email in emailAddresses
select new EmailAddressStats {
Total = membersQueryable.Any(m => m.Email == email),
Active = membersQueryable.Any(m => m.Email == email && m.IsActive)
}).ToList();
So if I pass in 3 email addresses, I see 6 separate queries (3 email addresses * 2 subqueries).
I've tried making the array queryable using .AsQueryable(), but I'm still getting the same result.
Ideally I would like EF to generate something like:
SELECT ([totalSubquery]) AS Total,
([activeSubquery]) AS Active
FROM ????
WHERE EXISTS ('email1#domain.com', 'email2#domain.com', 'email3#domain.com' )
NOTE: I am using Entity Framework 4.
I don't have EF4 installed, but you should be able to something like this to only perform a single query.
List<EmailAddressStats> GetEmailAddressStats(string[] emailAddresses)
{
var returnList = emailAddresses.Select(e => new EmailAddressStats { Email = e })
.ToList();
// I don't know what your context is actually called so I'm just calling it MemberDatabaseContext)
using (var dbContext = new MemberDatabaseContext())
{
// Query the database once with a single query to get all of the relevant members
var membersWithEmailAddress = dbContext.Members.Where(m => emailAddresses.Contains(m.Email))
.Select(m => new { Email = m.Email, IsActive = m.IsActive })
.ToList();
// Update the email stats by analyzing the member info in memory
foreach (var emailStat in returnList)
{
emailStat.Total = membersWithEmailAddress.Count(m => m.Email == emailStat.Email);
emailStat.Active = membersWithEmailAddress.Count(m => m.Email == emailStat.Email && m.isActive);
}
}
return returnList;
}
(sorry that this is in Fluent syntax instead of the Query Expression syntax, but I only know how to do this in Fluent syntax)

how to return the query result as a specific object type in LINQ

Sorry I'm new to LINQ and Entity framework.
When a linq query fetches a whole Entity,
how can i return the result as an object type?
I mean not just a field but also to return all the fields of that specific record, as one entity.
For example a Staff table in sql. To return a staff object entity.
if i write Linq code like this:
var db= (from c in context.Staff
where c.id == sId
select new { s.sId,s.staffNo,s.name,s.surname,s.image});
return db; ---> here
Gives an error because i want to return result as Staff object.
How can it return as a table column object?
Thank you
As per your comments, you need a single object returned from your method.
To return a single Item you have following options.
First: Returns first item from the collection, if there are no matching items then an exception would be thrown.
FirstOrDefault: Works same like First except it would return null if there are no matching records.
Single: Returns only one item from the list, It will throw exception if the collection contains more than one item or the collection is empty. A possible usage is when querying against primary key. Only one record should be returned. Exceptional case should be when there are more than one record.
SingleOrDefault: Works on the same principal as Single except it would return null if the collection is empty.
All these methods can be added at the end of your query syntax or could receive a predicate. Like:
var db= (from c in context.Staff
where c.id == sId
select c).FirstOrDefault();
Or
var db = context.Staff.FirstOrDefault(c=> c.id == sId);
If your field id is a primary key then use SingleOrDefault.
(Old Answer
If you are trying to return particular columns from a table, then you can't project your result to your class Staff since that is generated through the framework.
You have two options. First create another class with properties same as your result set and return its object.
Or instead of selecting specific columns, select all columns and then return Staff type object.
var db= from c in context.Staff
where c.id == sId
select c;
return db;
If you want to create an other class lets say PartialStaff then you can do:
var db= from c in context.Staff
where c.id == sId
select new PartialStaff
{
Id = s.sId,
//.......rest of the properties
};
But then your method return type should be PartialStaff type collection.
When a linq query fetches a whole Entity, how can i return the result
as an object type? I mean not just a field but also to return all the
fields of that specific column, as one entity.
For example a Staff table in sql. To return a staff object entity.
You could try this one:
var db= (from c in context.Staff
where c.id == sId
select c);
or
db = context.Staff.Where(s=>s.id == sId);
The result of the above query is a sequence of Staff objects, IEnumerable<Staff>. Specifically, this sequence will contain all the Staff objects in context.Staff, whose id is equal to sId.
Gives an error because i want to return result as Staff object.
Now If you are sure that there would be at most one item in context.Staff with the given id, you could try this:
var db = (from c in context.Staff
where c.id == sId
select c).SingleOrDefault();
or
var db = context.Staff.SingleOrDefault(s=>s.id == sId);
This query will return the single Staff object with the given id and if there isn't any Staff object in context.Staff with this id, will return null.

`from..where` or `FirstOrDefault` in LINQ

Traditionally, when I've tried to get data for a user from a database, and I've used the following method (to some degree):
DbUsers curUser = context.DbUsers.FirstOrDefault(x => x.u_LoginName == id);
string name = curUser.u_Name;
string email = curUser.u_Email;
You can see that all I want to do is get the Name and Email, but it seems to me that this LINQ query is getting everything stored in the database of that user, bringing it back, then allowing me to get what I want.
I have been doing some research and have found the following alternative:
var current = from s in context.DbUsers
where s.u_LoginName == id
select new {
name = s.u_Name,
email = s.u_Email
};
foreach (var user in current)
{
//Stuff Here
}
Which would be better, if any at all? Is there a lighter method to use when I only want to retrieve a few results / data?
If you want to get only two fields, then you should project your entity before query gets executed (and in this case query gets executed when you call FirstOrDefault). Use Select operator for projection to anonymous object with required fields:
var user = context.DbUsers
.Where(u => u.u_LoginName == id)
.Select(u => new { u.u_Name, u.u_Email })
.FirstOrDefault(); // query is executed here
string name = user.u_Name; // user is anonymous object
string email = user.u_Email;
That will generate SQL like:
SELECT TOP 1 u_Name, u_Email FROM DbUsers
WHERE u_LoginName = #id
In second case you are doing projection before query gets executed (i.e. enumeration started). That's why only required fields are loaded. But query will be slightly different (without TOP 1). Actually if you will convert second approach to lambda syntax, it will be almost same:
var query = context.DbUsers
.Where(u => u.u_LoginName == id)
.Select(u => new { u.u_Name, u.u_Email });
// query is defined but not executed yet
foreach (var user in query) // executed now
{
//Stuff Here
}
And just to show complete picture, without projection you get all fields of first found user:
DbUsers user = context.DbUsers
.Where(u => u.u_LoginName == id)
.FirstOrDefault(); // query is executed here
string name = user.u_Name; // user is DbUsers entity with all fields mapped
string email = user.u_Email;
In that case user entity is not projected before query is executed and you'll get all fields of user loaded from database and mapped to user entity:
SELECT TOP 1 u_LoginName, u_Name, u_Email /* etc */ FROM DbUsers
WHERE u_LoginName = #id
The second is better. You only get the needed data from database so the network traffic is lighter.
You can have the same result with extension methods:
var user = context.DbUsers
.Where(x => x.u_LoginName == id)
.Select(x => new {...})
.FirstOrDefault();
If you need not whole entity, but some values from it, then use new {name = s.u_Name, email = s.u_Email}. Because, this object is much "lighter" for cunstruction.
When you get entity with FirstOrDefault, it' saved in DBContext, but you don't do anything with it.
So, i advice you to get only data you need.

Linq to NHibernate: how to get a list of child objects without having the lists nested

I have a Linq to NHibernate query as follows:
var profile =
from UserProfile up in _Session.Query<UserProfile>()
.Fetch(x=>x.Messages)
where up.UserName == userName
select up.Messages;
this returns an IQueryable<IList<UserMessage>> which I then have to run a SelectMany() on. I'd prefer if I could just return an IQueryable<UserMessage> object instead, especially as the query will never return more than one user profile. Can this be done, or am I stuck with the extra step?
If you map the other side of the navigation e.g have a UserProfile property on the UserMessage class, your can start from UserMessage:
var messages =
from UserMessage um in _Session.Query<UserMessage>()
where um.UserProfile.UserName == userName
select um;
Otherwise you need to use SelectMany() to get a flattened out list.
Could you query the messages table directly and use the reverse association?
IQueryable<Message> messages = ...;
var filtered = from m in messages
where m.UserProfile.UserName == userName
select m;
Also, if you're willing to forgo query syntax you could make this shorter with:
var profile = _Session.Query<UserProfile>()
.Where(up => up.UserName == userName)
.SelectMany(up => up.Messages);

Using nested LINQ queries and collections of objects

I am using a two LINQ queries(nested)
Here's what I want my query to achieve:
In my inner query
Retrieve a collection of UserLocation objects using two conditions
In my outer query
Retrieve a filtered collection of User objects where User.UID matches the property UserLocation.UID of each UserLocation object from the collection in the inner query.
I'm almost there code-wise, I'm just missing the final step -- I don't know how to get the outer query to enumerate through the UserLocation collection and match the UID.
In my code I have two queries, the top one is a working example of getting the FullName property of a User object using the inner query and the conditions I need(as well as matching UID).
The second query is the one I am having trouble with. What am I missing?
ownerLiteral.Text =
Users.First(u => u.UID.Equals(
UserLocations.First(s => s.IsOwner == true && s.LID.Equals(building.LID)).UID)).FullName;
var propertyteam =
Users.Where(c => c.UID.Equals(
UserLocations.Where(x => x.IsPropertyTeam == true && x.LID.Equals(building.LID))));
Edit: Fixed the problem
I had forgotten that UserLocations was a member of Users -- I shortened down my query and used .Any to select the UserLocations members that fit my conditions, then just return the User.
In the first query I return the FullName for the User object.
In the second query I now return a collection of User objects that fit the conditions.
For those that are interested I bind the second query to a DataList and then evaluate for their FullName in the user control.
ownerLiteral.Text =
Users.First(
u => u.UserLocations.Any(
ul => ul.IsOwner == true && ul.LID.Equals(building.LID))).FullName;
var propertyteam =
Users.Where(
u => u.UserLocations.Any(
ul => ul.IsPropertyTeam && ul.LID.Equals(building.LID)));
Your class relationships are confusing me, but I think your problem is that you're trying to treat a collection of UserLocation objects (Where() returns an IEnumerable) as a single UserLocation
I think this might do it:
var propertyteam = LoggedInUser.ExtranetUser.Company.Users
.Where(c => c.UID.IsPropertyTeam == true && c.UID.LID.Equals(building.LID));
Edit, based on further information:
So maybe this is what you're looking for?
var uidsWhoArePartOfThePropertyTeamForThisBuilding
= UserLocations.Where(x => x.IsPropertyTeam && x.LID == building.LID)
.Select(x => x.UID);
Assuming the UID member of a UserLocation is a whole User object, and not just some int ID for a User.
To write a T-SQL type IN clause, in LINQ you would use Contains. This would be where I would start:
var userlocations = LoggedInUser.ExtranetUser.UserLocations.Select(ul => ul.UID);
var propertyteam = LoggedInUser.ExtranetUser.Company.Users.Where(userlocations.Contains(u => u.UID));

Categories

Resources