Remove whole group if value of grouped item is zero - c#

I have an object
public class ActiveUser
{
public int UserID { get; set; }
public string UserName { get; set; }
public string Location { get; set; }
public bool IsActive{ get; set; }
}
with data
List<ActiveUser> userList = new List<ActiveUser>();
userList.Add( new User { UserID = 1, UserName = "UserOne", Location = "LOne", IsActive= false } );
userList.Add( new User { UserID = 1, UserName = "UserOne", Location = "LTwo", IsActive= false } );
userList.Add( new User { UserID = 2, UserName = "UserTwo", Location = "LOne", IsActive= true } );
userList.Add( new User { UserID = 2, UserName = "UserTwo", Location = "LTwo", IsActive= false } );
userList.Add( new User { UserID = 2, UserName = "UserTwo", Location = "LThree", IsActive= true } );
userList.Add( new User { UserID = , UserName = "UserThree", Location = "LOne", IsActive= true } );
What I Want?
I want to select data with the following condition using LinQ or lambda expressions using C#.
If we group by UserID, in that group, if IsActive is false for all the row, then that group need not be selected.
If the group contains at least one IsActive as True, then we have to select all the rows in the group including IsActive = false
So the output should be like all rows with UserID = 1 get removed and all other rows get included.
I tried something like this and i'm stuck. I dont have any idea how to use this.
userList.GroupBy(c => c.UserID).Select(g => g.UserName )
Any help would be much appreciated.
Thanks

If you want to alter the original list, then a for loop is more appropriate. If you want to create a new list with just the items that have at least one active item, then you can add a Where after the GroupBy:
var query = userList.GroupBy(c => c.UserID)
.Where(g => g.Any(c => c.IsActive))
note that you can't do Select(g => g.UserName) because the output of a GroupBy is a collection of groups, and the groups do not expose the properties of the items within them. If you want to project the original items instead of groups, use SelectMany to "flatten" the groups:
var query = userList.GroupBy(c => c.UserID)
.Where(g => g.Any(c => c.IsActive))
.SelectMany(g => g)

You can use group.Any(u => u.IsActive)
var allWithAtLeastOneActiveUser = userList
.GroupBy(c => new { c.UserID, c.UserName })
.Where(g => g.Any(u => u.IsActive));
If you want to flatten these groups:
List<ActiveUser> allWithAtLeastOneActiveUser = userList
.GroupBy(c => new { c.UserID, c.UserName })
.Where(g => g.Any(u => u.IsActive))
.SelectMany(g => g)
.ToList();

Related

C# Linq - EF, select grouped data having the max value

I have a many to many table where I store UserId, SectionId, Attempt, Qualification and timestamps. So, the user can have N Attempts by Section but when I evaluate every section only need to take where the Attempt is the max value.
I tried make a join with the keys UserId and SectionId ordering desc by Attempt
var result = await (from exam in db.exams
join section in db.sections on exam.SectionId equals section.Id
join groupedTable in (from exam2 in db.exams
group exam2 by new { UserId = exam2.UserId, SectionId = exam2.SectionId, Attempt = exam2.Attempt } into grouped
select new { UserId = grouped.Key.UserId, SectionId = grouped.Key.SectionId, LastAttempt = grouped.Max(x => x.Attempt) })
.OrderByDescending(x => x.LastAttempt)
.Select(x => new
{
UserId = x.UserId,
SectionId = x.SectionId,
LastAttempt = x.LastAttempt
})
on new { UserId = exam.UserId, SectionId = section.Id }
equals new { UserId = groupedTable.UserId, SectionId = groupedTable.SectionId }
select exam)
.Distinct()
.ToListAsync();
also tried this
var result = await (from exam in db.exams
join section in db.sections on exam.SectionId equals section.Id
select new
{
UserId = exam.UserId,
SectionId = exam.SectionId,
Attempt = exam.Attempt
})
.GroupBy(x => new
{
x.UserId,
x.SectionId,
x.Attempt
})
.Select(x => new
{
UserId = x.Key.UserId,
SectionId = x.Key.SectionId,
Attempt = x.Max(x => x.Attempt)
})
.ToListAsync();
but the result is the same:
{ UserId = {e56e13b6-28e5-46b2-bd78-f975fd96e1a7}, SectionId = 8, Attempt = 1 }
{ UserId = {e56e13b6-28e5-46b2-bd78-f975fd96e1a7}, SectionId = 10, Attempt = 1 }
{ UserId = {e56e13b6-28e5-46b2-bd78-f975fd96e1a7}, SectionId = 9, Attempt = 1 }
{ UserId = {e56e13b6-28e5-46b2-bd78-f975fd96e1a7}, SectionId = 10, Attempt = 2 }
I this example I need to exclude where SectionId = 10 and Attempt = 1
You keep grouping by Attempt, which means every user+section+attempt becomes its own group (probably of size 1)
Remove Attempt from the grouping part of the operation; only group by user and section
It might be clearer to explain using SQL. You are doing this:
SELECT user, section, attempt, MAX(attempt) --max is useless here
FROM ...
GROUP BY user, section, attempt --always a group size of 1
You need to do this:
SELECT user, section, MAX(attempt)
FROM ...
GROUP BY user, section
var result = await (from exam in db.exams
join section in db.sections on exam.SectionId equals
section.Id
select new
{
UserId = exam.UserId,
SectionId = exam.SectionId,
Attempt = exam.Attempt
})
.GroupBy(x => new
{
x.UserId,
x.SectionId
})
.Select(x => new
{
UserId = x.Key.UserId,
SectionId = x.Key.SectionId,
Attempt = x.Max(c => c.Attempt)
})
.ToListAsync();
try this it will work.

How can I distinct with condition?

Here is class UserArrived:
public class UserArrived{
public string id{get;set;}
}
Here is class OldUser:
public class OldUser{
public string id{get;set;}
public DateTime lastArrived{get;set;}
}
And here is class User:
public class User{
public string id{get;set;}
public Boolean newUser{get;set;}
}
Finally, here is two List:
List<UserArrived> UserArrivedList=new List<UserArrived>();
List<OldUser> OldUserList=new List<OldUser>();
All the id in each class is unique.
Now I need to combine UserArrived and OldUser to a brand new List<User>.
As we know, the user arrives the shop may is a new user or an old user. If the user id in UserArrived also contains in OldUser, the property newUser in the new List is false for true.
In my opinion, I will combine two List into one first and then use the distinct method to remove the duplicates.
However, it seems the distinct can not run with a condition.
Although I can use several foreach to solve this while I feel it is so troublesome. I want to use something easy just like lambda or linq. How can I achieve this?
=============================
Here is an example of the input:
List<UserArrived> UserArrivedList=new List<UserArrived>(){new UserArrived(){id="A"},new UserArrived(){id="B"},new UserArrived(){id="C"}};
List<OldUser> OldUserList=new List<OldUser>(){new OldUser(){id="B",lastArrived=DateTime.Now}};
the output is:
A,true
B,false
C,true
If I understand your requirement you're saying that if an id is in both lists then the user is an old user, otherwise it is a new user.
So here's the simplest way that I could come up with to do it:
IEnumerable<User> users =
Enumerable
.Concat(
UserArrivedList.Select(i => i.id),
OldUserList.Select(i => i.id))
.ToLookup(x => x)
.Select(x => new User() { id = x.Key, newUser = x.Count() == 1 });
Let's test with some input:
var UserArrivedList = new List<UserArrived>()
{
new UserArrived() { id = "A" },
new UserArrived() { id = "B" },
};
var OldUserList = new List<OldUser>()
{
new OldUser() { id = "B" },
new OldUser() { id = "C" },
};
Here are my results:
B is the only user who appears in both lists so should be False.
So, there's a bit of confusion about the requirements here.
The OP has added a concrete example of the input data and the expected output.
var UserArrivedList = new List<UserArrived>()
{
new UserArrived() { id = "A" },
new UserArrived() { id = "B" },
new UserArrived() { id = "C" }
};
var OldUserList = new List<OldUser>()
{
new OldUser() { id = "B", lastArrived = DateTime.Now }
};
With this input the OP is expecting True, False, True for A, B, C respectively.
Here is the code of the four current answers:
var results = new []
{
new
{
answered = "Enigmativity",
users = Enumerable
.Concat(
UserArrivedList.Select(i => i.id),
OldUserList.Select(i => i.id))
.ToLookup(x => x)
.Select(x => new User() { id = x.Key, newUser = x.Count() == 1 })
},
new
{
answered = "JQSOFT",
users = UserArrivedList.Select(x => x.id)
.Concat(OldUserList.Select(y => y.id))
.Distinct()
.Select(x => new User
{
id = x,
newUser = OldUserList.Count(o => o.id == x) == 0,
})
},
new
{
answered = "Anu Viswan",
users =
UserArrivedList
.Join(OldUserList, ual => ual.id, oul => oul.id, (ual, oul) => new User { id = oul.id, newUser = false })
.Concat(UserArrivedList.Select(x => x.id).Except(OldUserList.Select(x => x.id))
.Concat(OldUserList.Select(x => x.id).Except(UserArrivedList.Select(x => x.id)))
.Select(x=> new User{ id = x, newUser = true}))
},
new
{
answered = "Barns",
users =
UserArrivedList.Select(i => i.id)
.Union(OldUserList.Select(i => i.id))
.Select(j => new User
{
id = j,
newUser =
!(UserArrivedList.Select(i => i.id).Contains(j)
&& OldUserList.Select(i => i.id).Contains(j))})
}
};
That gives the output of:
So, currently all of the answers presented match the OP's example.
I'd be interested in the OP commenting on this as the input data:
var UserArrivedList = new List<UserArrived>()
{
new UserArrived() { id = "A" },
new UserArrived() { id = "B" },
};
var OldUserList = new List<OldUser>()
{
new OldUser() { id = "B" },
new OldUser() { id = "C" },
};
When I run this I get this output:
Here three users match and one does not.
This all boils down to what the description means:
As we know, the user arrives the shop may is a new user or an old user. If the user id in UserArrived also contains in OldUser, the property newUser in the new List is false for true.
The thing about LINQ--it isn't always easy. In fact it can get quit cluttered. In the question statement I read,
I want to use something easy just like lambda or linq.
Well, that is relative. But, I think that when using LINQ, one should try to keep it simple. Even break the statement down into multiple statements if necessary. For that reason I propose this solution (demonstrated in a console app):
static void Main(string[] args)
{
Console.WriteLine();
Console.WriteLine("--------------------Test This Code -----------------------");
var combined = TestUserCombined();
//The following is just to demonstrate the list is populated properly
combined.OrderBy(s => s.id.PadLeft(4, '0')).ToList().ForEach(k => Console.WriteLine($"X id: {k.id} | isNew:{k.newUser}"));
}
private static IEnumerable<User> TestUserCombined()
{
List<UserArrived> userArrivedList=new List<UserArrived>();
List<OldUser> oldUserList=new List<OldUser>();
//populate the lists...
for(int i = 0; i < 20; i+=2)
{
var userArrived = new UserArrived();
userArrived.id = i.ToString();
userArrivedList.Add(userArrived);
}
for(int i = 0; i < 20; i+=3)
{
var oldUser = new OldUser();
oldUser.id = i.ToString();
oldUserList.Add(oldUser);
}
//Now for the solution...
var selectedUserArrived = userArrivedList.Select(i => i.id);
var selectedOldUser = oldUserList.Select(i => i.id);
var users = selectedUserArrived
.Union(selectedOldUser)
.Select(j => new User{id=j,newUser=!(selectedUserArrived.Contains(j) && selectedOldUser.Contains(j))});
return users;
}
Certainly, this all could have been done in one statement, but I believe this makes it more readable and understandable.
EDIT:
There has been some discussion amongst the coders posting solutions as to exactly what conditions must be met in order for the value "newUser" to be set to "true". It was my understanding from the initial posted question that the "id" must be present in both lists "UserArrivedList" AND "OldUserList", but I tend to agree with #JQSOFT that it makes more sense that the only condition that must be met should be that the "id" need only be present in "OldUserList". If that is indeed the case than the Select() expression above should be .Select(j => new User{id=j,newUser=!selectedOldUser.Contains(j)});
I hope I understood your query. One way to achieve this using Linq would be
var users = UserArrivedList.Join(OldUserList,ual=>ual.id,oul=>oul.id,(ual,oul)=>new User{id=oul.id,newUser=false})
.Concat(UserArrivedList.Select(x=>x.id).Except(OldUserList.Select(x=>x.id))
.Concat(OldUserList.Select(x=>x.id).Except(UserArrivedList.Select(x=>x.id)))
.Select(x=> new User{id=x,newUser=true}));
Now you need to create a distinct list of User type from two lists of different types; UserArrived and OldUser objects. A user is identified by a unique id of string type.
Accordingly, I'd suggest this:
var users = UserArrivedList.Select(x => x.id)
.Concat(OldUserList.Select(y => y.id))
.Distinct()
.Select(x => new User
{
id = x,
newUser = OldUserList.Count(o => o.id == x) == 0,
}).ToList();
Which gets the unique ids from both UserArrivedList and OldUserList and creates new User object for each. The OldUserList.Count(o => o.id == x) == 0, assigns false to the newUser property if the user id exists in the OldUserList otherwise true.

How to sort data based on CreatedUtc Date using mongodb query in c#?

I want to sort the data based on CreatedUtc time. I have tried to use Reverse function, it seems to work out but still looking for some alternate option.
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).ToList().Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().ToList();
There are 2 things you need to concern:
You can sort the elements of a sequence by using OrderBy
You should not .ToList() when you have not done, So you might to read LINQ deferred (or immediate?) execution to have a better understanding.
As a result, your query should look like this
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().OrderBy(g => g.CreatedUtc).ToList();
How about .OrderBy(g => g.CreatedUtc) ?

LINQ not sorting List<> properly

My EF query is supposed to be sorting by the date of the first Product in the list, but for some reason, it only sorts most of the products and some of the dates are in the wrong order.
Here's the code...
using (var context = new SalesEntities())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
return lst;
}
Code seems good to me, but look at how one of the dates is out of order...
weird sorting http://www.84sales.com/weird_sort.png
Try doing the order by on the inital select
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID,
c.s84_Customer.CustomerName,
c.SubdivisionID,
c.s84_Subdivision.SubdivisionName,
c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).OrderBy(x => x.CustomerExpectedDate).ToList()
});
The problem is the .First() function, witch returns the first record, but not necessarly in date order. if you wich to order your grouped datas by date so that the First() function returns the most recent date, you'll need to order your datas before grouping them, and then REorder your results with the First()function :
using (var context = PrimaryConnection.returnNewConnection())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).Orderby(t => t.CustomerExpectedDate).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
All SQL queries (and hence Linq queries, when attached to a SQL database) have a random order, unless you sort them.
Products is not sorted - hence it has a random order.
You sort by Products.First(), but Products has a random order, so your sort will also be random.
Make sure Products is sorted within the query, and you should be ok.
Products = grouped.Select(....)
.OrderBy(x => x.ProductDate)
.ToList()

Merging 2 C# IQueryable

I don't have a lot of experience with IQueryable
What I am trying to do is search for a user based on a list of passed in constraints that can either be a username, or phone number. Depending on the type I want to return limited information. I then want to combine the 3 IQueryables into one and combine entries with matching id and username to maintain the most information.
Here is what i have so far:
public IQueryable<User> Search(String[] criteria)
{
var query = Database.Get<User>();
IQueryable<User> phoneQuery = null;
IQueryable<User> emailQuery = null;
IQueryable<User> nameQuery = null;
foreach (String str in criteria)
{
// Check if it is a phone number
if (Regex.IsMatch(str, #"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
{
phoneQuery = query.Where(
u => u.PhoneNumber.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
PhoneNumber = i.PhoneNumber
})
}
// check if it is an email
else if (criteria.Contains("#"))
{
emailQuery = query.Where(
u => u.Email.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
Email = i.Email
})
}
else
{
nameQuery = query.Where(
u => u.UserName.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
})
}
}
// Merge the 3 queries combining entries if the username and id match and maintain the maximum amount of information
return query;
}
There are a few issues with your code:
ToList() will execute the query. If you call AsQueryable() later, you simply create an object query on the local objects. This basically loses the notion of IQueryable, so you'd better delete all ToList() and AsQueryable() calls.
You can make it a single query instead of merging the three queries, like so:
Expression predicateBody = Expression.Constant(false);
Expression userParameter = Expression.Parameter("user", typeof(User));
Expression userUserName = Expression.MakeMemberAccess(...);
Expression userPhoneNumber = Expression.Cal(...);
Expression userEmail = Expression.Call(...);
foreach (String str in criteria)
{
// Check if it is a phone number
if (Regex.IsMatch(str, #"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
{
predicateBody = Expression.Or(predicateBody, Expression.Equals(userPhoneNumber, Expression.Constant(str)));
}
// check if it is an email
else if (criteria.Contains("#"))
{
predicateBody = Expression.Or(predicateBody, Expression.Equals(userEmail, Expression.Constant(str)));
}
else
{
predicateBody = Expression.Or(predicateBody, Expression.Equals(userUserName, Expression.Constant(str)));
}
}
return query.Where(Expression.Lambda<Func<User, bool>>(predicateBody, userParameter))
.GroupBy(u => u.Id)
.Select(users => new User()
{
Id = users.Key,
UserName = users.Select(u => u.UserName).Intersect(criteria).FirstOrDefault(),
Email = users.Select(u => u.Email).Intersect(criteria).FirstOrDefault(),
PhoneNumber = users.Select(u => u.PhoneNumber).Intersect(criteria).FirstOrDefault()
});
Edit Sorry, I misunderstood the merging problem.
Edit2 If the criterias are sorted in advance, there is also a solution that does not require to manually creating the expression tree.
Edit3 I see, I forgot the part with the limited information.
var phoneNumbers = new List<string>();
var emails = new List<string>();
var userNames = new List<string>();
foreach (var str in criteria)
{
// Check if it is a phone number
if (Regex.IsMatch(str, #"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
{
phoneNumbers.Add(criteria);
}
// check if it is an email
else if (criteria.Contains("#"))
{
emails.Add(crietria);
}
else
{
userNames.Add(criteria);
}
}
return query.Where(u => phoneNumbers.Contains(u.PhoneNumber)
|| emails.Contains(u.Email)
|| userNames.Contains(u.UserName))
.GroupBy(u => u.Id)
.Select(users => new User()
{
Id = users.Key,
UserName = users.Select(u => u.UserName).Intersect(userNames).FirstOrDefault(),
Email = users.Select(u => u.Email).Intersect(emails).FirstOrDefault(),
PhoneNumber = users.Select(u => u.PhoneNumber).Intersect(phoneNumbers).FirstOrDefault()
});
This is what I ended up going with.
public IQueryable<User> Search(String[] criteria)
{
var query = Database.Get<User>();
List<User> res = new List<User>();
foreach (String str in criteria)
{
// Check if it is a phone number
if (Regex.IsMatch(str, #"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
{
var users = query.Where(
u => u.PhoneNumber.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
Email = null,
PhoneNumber = i.PhoneNumber
});
// Multiple users can have the same phone so add all results
foreach (User u in users)
{
if (u != null) { res.Add(u); }
}
}
// Check if it is an email match
else if (str.Contains("#"))
{
var user = query.Where(
u => u.Email.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
Email = i.Email,
PhoneNumber = null
}).SingleOrDefault<User>(); // Only one user can use an email
if (user != null) { res.Add(user); }
}
// Otherwise it is a username
// NOTE: If a username is all digits and dashes it won't be
// searched for because it is interpreted as a phone number!
else
{
var user = query.Where(
u => u.UserName.ToLower() == (str))
.Select(i => new User
{
Id = i.Id,
UserName = i.Name,
Email = null,
PhoneNumber = null
}).SingleOrDefault<User>(); // Only one user can use an email
if (user != null) { res.Add(user); }
}
}
query = res.AsQueryable();
// Group the results by username and id and return all information that was found
query = from u in query
group u by new
{
u.Id,
u.UserName
} into g
select new User()
{
Id = g.Key.Id,
UserName = g.Key.UserName,
Email = g.Select(m => m.Email).SkipWhile(string.IsNullOrEmpty).FirstOrDefault(),
PhoneNumber = g.Select(m => m.PhoneNumber).SkipWhile(string.IsNullOrEmpty).FirstOrDefault()
};
return query;
}

Categories

Resources