How to select data only with a unique email field? - c#

I need to select data from a table. The data has an Email field which is not unique. Now i only want to select the first item with an Email of its kind and ignore the others.
I tried:
var users = _context.Appointments.Where(p => (p.userId == userId))
.Select(p => new MyUserModel
{
Id = p.Id,
Email = p.User.Email
});
return users.ToList();
I wanted to use Distinct(), but my elements are not unique, they have a different id.
How could I go about doing that?

However, if this field is repeated, then I do not need to select this
element
You can group by the email and then perform a filter to retain the objects that don't repeat by email and then follow it with your current logic. Example:
var users = _context.Appointments
.Where(p => p.userId == userId)
.GroupBy(p => p.User.Email)
.Where(g => g.Count() == 1) // if there is only one object with this email, then retain it otherwise discard it
.Select(g => g.First())
.Select(p => new MyUserModel
{
Id = p.Id,
...
Email = p.User.Email
...
});
return users.ToList();

Related

How do I to use Where, Group By, Select and OrderBy at same query linq?

I'm trying to make a linq using where, group by and select at same time but I cannot do it works and it always throws an exception.
How could I do it works ?
Linq
public ActionResult getParceiros(){
//return all partners
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.GroupBy(x => x.id)
.OrderBy(x => x.nomeParceiro)
.ToList();
return View(lista);
}
Exception
Your program doesn't do what you want. Alas you forgot to tell you what you want, you only showed us what you didn't want. We'll have to guess.
So you have a sequence of Usarios.
IQueryable<Usario> usarios = ...
I don't need to know what a Usario is, all I need to know is that it has certain properties.
Your first step is throwing away some Usarios using Where: you only want to keep thos usarios that have a Perfil equal to RoleType.Parceirdo:
// keep only the Usarios with the Perfil equal to RoleType.Parceirdo:
var result = usarios.Where(usario => usario.Perfil == RoleType.Parceirdo)
in words: from the sequence of Usarios keep only those Usarios that have a Perfil equal to RoleTyoe.Parceirdo.
The result is a subset of Usarios, it is a sequence of Usarios.
From every Usario in this result, you want to Select some properties and put them into one ViewParceirosModel:
var result = usarios.Where(usario => usario.Perfil == RoleType.Parceirdo)
.Select(usario => new ViewParceirosModel
{
Id = x.id,
NomeParceiro = x.nome,
EmailAcesso = x.email,
})
In words: from every Usario that was kept after your Where, take the Id, the Nome and the Email to make one new ViewParceirosModel.
The result is a sequence of ViewParceirosModels. If you add ToList(), you can assign the result to your variable lists.
However your GroupBy spoils the fun
I don't know what you planned to do, but your GroupBy, changes your sequence of ViewParceirosModels into a sequence of "groups of ViewParceirosModels" Every ViewParceirosModel in one group has the same Id, the value of this Id is in the Key.
So if after the GroupBy you have a group of ViewParceirosModel with a Key == 1, then you know that every ViewParceirosModel in this group will have an Id equal to 1.
Similarly all ViewParceirosModel in the group with Key 17, will have an Id equal to 17.
I think Id is your primary key, so there will only be one element in each group. Group 1 will have the one and only ViewParceirosModel with Id == 1, and Group 17 will have the one and only ViewParceirosModel with Id == 17.
If Id is unique, then GroupBy is useless.
After the GroupBy you want to Order your sequence of ViewParceirosModels in ascending NomeParceiro.
Requirement
I have a sequence of Usarios. I only want to keep those Usarios with a Perfil value equal to RoleType.Parceirdo. From the remaining Usarios, I want to use the values of properties Id / Nome / Email to make ViewParceirosModels. The remaining sequence of ViewParceirosModels should be ordered by NomeParceiro, and the result should be put in a List.
List<ViewParceirosModel> viewParceiroModels = Usarios
.Where(usario => usario.Perfil == RoleType.Parceirdo)
.Select(usario => new ViewParceirosModel
{
Id = x.id,
NomeParceiro = x.nome,
EmailAcesso = x.email,
}
.OrderBy(viewParceirosModel => viewParceirosModel.NomeParceiro)
.ToList();
When you create a LINQ query with group by clause, you receive as result a grouped query.
It is a kind of dictionary that has as key the field you chose to group and as value a list of records of this group.
So, you cannot order by "nomeParceiro" because this field is inside the group.
If you detail how you expect the result I can show you a code example for this.
You can find more details in this section of the doc: https://learn.microsoft.com/pt-br/dotnet/csharp/linq/group-query-results
Let's say ViewParceirosModel look like
public class ViewParceirosModel
{
public int id {get; set;}
public List<string> nomeParceiro {get; set;}
public List<string> emailAcesso {get; set;}
}
After that, you can Groupby then select combine with Orderby like below
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.GroupBy(x => x.id)
.Select(g => new ViewParceirosModel
{
id = g.Key,
nomeParceiro = g.Select(p => p.nomeParceiro).OrderBy(x => x.nomeParceiro).ToList()
nomeParceiro = g.Select(p => p.emailAcesso).ToList()
})
.ToList();
You can use the following code.
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.OrderBy(x => x.nomeParceiro)
.GroupBy(x => x.id)
.ToList();
or
List<List<ViewParceirosModel>> listb = context.usuarios
.Where(u => u.perfil == RoleType.Parceiro)
.GroupBy(g => g.id).OrderBy(g => g.Key)
.Select(g => g.OrderBy(x => x.nomeParceiro)).ToList();

How I can optimize my LINQ query?

I have written following LINQ query to return list of Groups and then iterating list separately.
I only need list of Groups of User with specific email.
I am sure this might not be the right away.
Can i re-write it in a better way (performance-wise) ?
var groups = _context.Users.Where(m => m.Email == email)
.Include(g => g.Customer)
.ThenInclude(r => r.CustomerGroups)
.ThenInclude(t => t.Group)
.First().Customer.CustomerGroups;
foreach (var group in groups)
{
var s = group.Group;
//do something
}
If you need just CustomerGroup entities with the related Group entity (as I interpret your clarification in the comment section) it's inefficient to fetch other related entities (User and Customer). You can make EF to fetch only the entities you are interested in like this:
var groups =
(
from user in _context.Users
from customerGroup in user.Customer.CustomerGroups
where user.Email == email
select customerGroup
).Include(cg => cg.Group);
Or when CustomerGroup stores no relevant data, just relationships:
var groups =
(
from user in _context.Users
from customerGroup in user.Customer.CustomerGroups
where user.Email == email
select customerGroup.Group
);
Try this :
That is make query on CustomerGroups table so You don't need Include Customer and CustomerGroups .
var customerGroups = _context.CustomerGroups.Where(m => m.Customer.User.Email == email)
.Include(t => t.Group).
Select(s=> new CustomerGroupModel {
A= s.A,
B= s.B,
…
Group = s.Group
}).ToList();
Or
var customerGroups = _context.Customer.Where(m => m.User.Email == email)
.Include(r => r.CustomerGroups).ThenInclude(t => t.Group).
Select(s=> new CustomerGroupModel {
A= s.CustomerGroups.A,
B= s.CustomerGroups.B,
…
Group = s.CustomerGroups.Group
}).ToList();

NHibernate .SelectList() with List<string> in C#

I have a database request which looks as follows:
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.Query<User>()
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
It gets all users that the requesting user is allowed to see, depending on his own profession. Now I wanna restrict that a little more, that he can only see some attributes of the users. Let's say for example:
id -> yes
firstname -> yes
lastname -> yes
address -> no!
Now I tried t change the query to something like:
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.QueryOver<User>()
.SelectList(list => list
.Select(a => a.id)
.Select(a => a.firstname)
.Select(a => a.lastname))
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
Now my question... Is there a way to, for example, make a new List with these attributes and then loop through it? Something like that:
List<string> attributes = new List<string>(){"id", "firstname", "lastname"}
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.QueryOver<User>()
.SelectList(
//loop through attributes
)
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
Thanks in advance :-)
EDIT
To make my question a little bit more clear. I wanna have the attributes that the user is allowed to see, dynmically changeable from a List<string> outside the query.
How can a achieve that?
You could do
.Where(a => userProfessions.Contains(a.Profession.Id))
.Select(c => new User {
id = c.id,
firstname = c.firstname,
lastname = c.lastname,
address c.address
}).ToList();
I am assuming list is type of User. Other wise you could use anonymous return i.d. c => new { id="id",... }

block access by query result

I have Hospitals and Medical Specialities.
My Medical Specialities page return data by hospital ID in this way:
localhost/MedicalSpecialities/1, 1 is the HospitalID. if I change manually the link I can access any hospital info.
I have users associated to hospitals in this way:
I need to query the Hospital ID's that user have associated AND check if the current HospitalID is on the list.
This return all hospitals that user have connected:
var userID = User.Identity.GetUserId();
var result = db.Hospitals.Include("UserHospitals")
.Where(x => x.UserHospitals
.Any(u => u.Id == userID))
.ToList();
You can basically update the condition in your Any() method to include a check against the HospitalId column.
var hospitalId =5;
var result = db.Hospitals
.Include(y=>y.UserHospitals)
.Where(x => x.UserHospitals.Any(u => u.Id == userID
&& u.HospitalID==hospitalId ))
.ToList();
If you are expecting only a single hospital for this condition, you may also consider using FirstOrDefault() method.
var singleHospital = db.Hospitals
.Include(y=>y.UserHospitals)
.Where(x => x.UserHospitals.Any(u => u.Id == userID
&& u.HospitalID==hospitalId ))
.FirstOrDefault();
if(singleHospital!=null)
{
//Safely use it.
}

How to select multiple column and distinct one column by LINQ?

I have:
var names = db.tblPosts.Select(x => new { x.UserID, x.title }).Distinct().ToList();
I want select UserID and title and UserID is distinct.
but not worked and userID is not distinct..
var items = db.tblPosts
.GroupBy(x => x.UserId)
.Select(g => new { UserId = g.Key, Title = g.FirstOrDefault().Title })
.ToList();
It will return first Title for each UserId. Add additional OrderBy/ThenBy to sort items within group before taking first one.

Categories

Resources