`from..where` or `FirstOrDefault` in LINQ - c#

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.

Related

I want to select (Event) in which all the (Users) are registered in event

string value = "bse161063";
var inst = db.User_Register_Events.Where(c => c.UserTable.User_id == value).Select(x => x.UserTable.User_id).ToList().FirstOrDefault();
I have an issue in the below given query.
var userid = db.User_Register_Events.Where(c=>c.EventTable.Event_Title.Contains(value)).ToList();
var query = List.Where(UserTable => User_Id == value);
I want to select the (events) which are registered by a specific (user).
If I understand correctly by your screenshot what you're asking, then I gather you want to get all events for a user based on a search of the user's Name in the UserTables table. In that case the following should do the trick. It starts off in the UserTables table, then makes two hops to get the event Details from the EventTables table.
string userName = "Muhammad";
db.UserTables.Where(ut => ut.Name == userName).Select(ut => ut.User_Register_Events.Select(ure => ure.EventTable)).ToList();
If you're getting the events by just the user's Id then the query would be somewhat simpler, as you can start off in the User_Register_Event table like so
string userId = "bse161063";
db.User_Register_Events.Where(ure => ure.UserTableId == userId).Select(ure => ure.EventTable).ToList();
Ultimately, both queries will return a collection of EventTable based on the Select() projection here.

Fetching only one column from a table via where and select LINQ statement

I have written two queries which look like:
var loggedUser2 = ctx.Users.Where(y => y.Email == User.Identity.Name).Select(usr => new Users { UserId = usr.UserId }).AsEnumerable();
And second query looks like this:
var loggedUser = ctx.Users.FirstOrDefault(y => y.Email == User.Identity.Name);
The second query noticabely takes much more time to pull a single record from a table from a remote server as I can tell.
For the first query I'm getting an error:
The entity or complex type 'Users' cannot be constructed in a LINQ to Entities query.
when I try to access the property UserId of the "Users" object.
Now I have a couple of questions:
Why do I get this error and how do I actually access a property of a collection which is IEnumerable? I get it that I can materialize the query by using .ToList() and then have it accessed at [0].UserId, but I don't think this is the right way to do it?
What is the most efficient way to select a single column for a single records from a table (UserId in my case)? How would that query looks like (besides using a stored procedure).
Can someone help me out ? :)
you can declare a DTO or you can use an anonymous type like this:
var user = ctx.Users
.Where(u => u.Email == email)
.Select(u => new { UserId = u.UserId })
.FirstOrDefault()

linq: aggregate into single line (flatten)

I am currently using a linq and accessing some meta data using a for loop:
public SignUpMeta GetSignUpMeta(User user)
{
var users = (from u in User
where user.Email == u.Email || user.UserName == u.UserName
select u);
var result = new SignUpMeta();
foreach (var u in users)
{
if (user.Email == u.Email) result.IsDuplicateEmail = true;
if (user.UserName == u.UserName) result.IsDuplicateUserName = true;
}
return result;
}
Is there any way for the Linq to generate the SignUpMeta directly?
This function is inside the DBContext class and I am looking for a way to get the exact data directly from the db (without raw sql).
Update:
The User is DbSet and the whole code runs inside the db context class. I am trying to write something that will make EF fetch the value directly in a single query.
Update 2:
The SQL equivalent of what I am looking for would be:
SELECT MAX(username), MAX(email)
(SELECT CAST((UserName = #user) AS bit) username,
CAST((Email = #email) AS bit) email
FROM User WHERE UserName = #user OR Email = #email)
Update 3:
SignUpMeta object that needs to be fetched contains the metadata that provides information required for server side validation.
The above C# code runs a query that fetches up to two columns in this instance. When there are more such conditions, there would be more lines. I am trying to find a way that EF would give only the two booleans alone in a single record.
This'll be my try, if you truly must use LINQ:
from u in stuff.Users
group u by 0 into grp
select new
{
IsDuplicateEmail = grp.Any(x => x.Email == user.Email),
IsDuplicateUserName = grp.Any(x => x.UserName == user.UserName)
}
Entity Framework will translate that into sub-selects. If you're using SQL Server and have both columns indexed, this should result in the same amount of I/O as your sample SQL.
I don't believe there is any query that will generate your desired sample SQL.
I think this will be the fastest query:
public SignUpMeta GetSignUpMeta(User user)
{
return new SignUpMeta()
{
IsDuplicateEmail = User.Where(u => u.Email == user.Email).Take(1).Any(),
IsDuplicateUserName = User.Where(u => u.UserName == user.UserName).Take(1).Any(),
};
}
Caching on the DB server should make the two queries quite fast.

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)

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);

Categories

Resources