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();
Related
I'm trying to work out the Entity Framework syntax to return the User.Name, User.Email for the given Profile.email.
1 profile can have N categories. 1 category can have 1 User.
Profile - ID, email, Name, CreatedDate
Category - ID, ProfileId, Name, UserID
User - ID, Name, Email
In SQL I would write:
SELECT U.NAME, U.EMAIL
FROM PROFILE P
JOIN CATEGORY C ON P.ID = C.PROFILEID
JOIN USER U ON C.USERID = U.ID
WHERE P.EMAIL = 'SOME#EMAIL.COM'
Here is what I tried:
var data = await _context.Profiles
.AsNoTracking()
.Where(p => p.Categories.Users.email == 'some#email.com')
.Select(u => new
{
UName = u.Name,
UEmail = u.Email
}).ToListAsync();
The problem is that p.Categories is an ICollection, so I don't know how to proceed because p.Categories doesn't give me access to the .Users. I can write p.Categories.Where.... but I'm not sure how to proceed.
Instead of starting with _context.Profiles. should I be starting with _context.Users.?
Can someone help me on how to think about the approach when writing the Entity Framework query?
If I understood your model correctly, this should work:
var data = await _context.Categories.AsNoTracking()
.Where(c=>c.Profile.email == "some#email.com")
.Select(c=>new {
UName=c.User.Name,
UEmail=c.User.Email
}).ToListAsync();
Ofcourse this requires your model to have navigation properties set.
So just start your query the Categories in LINQ form:
from c in _context.Categories
where c.Profile.Email == someEmail
select new { c.User.Name, c.User.Email }
or in Lambda form:
_context.Categories
.Where( c => c.Profile.Email == someEmail )
.Select( c => new {c.User.Name, c.User.Email}
or start from Profiles and use SelectMany, whose LINQ form looks like
from p in _context.Profiles
from c in p.Categories
where p.Email == someEmail
select new {c.User.Name, c.User.Email}
or in Lambda form:
_context.Profiles
.Where(p => p.Email == someEmail)
.SelectMany(p => p.Categories)
.Select( c => new {c.User.Name, c.User.Email} )
Consider the following LINQ statements:
var model = getModel();
// apptId is passed in, not the order, so get the related order id
var order = (model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId));
var orderId = 0;
var orderId = order.LastOrDefault();
// see if more than one appt is associated to the order
var apptOrders = (model.getMyData
.Where(x => x.OrderId == orderId)
.Select(y => new { y.OrderId, y.AppointmentsId }));
This code works as expected, but I could not help but think that there is a more efficient way to accomplish the goal ( one call to the db ).
Is there a way to combine the two LINQ statements above into one? For this question please assume I need to use LINQ.
You can use GroupBy method to group all orders by OrderId. After applying LastOrDefault and ToList will give you the same result which you get from above code.
Here is a sample code:
var apptOrders = model.getMyData
.Where(x => x.ApptId == apptId)
.GroupBy(s => s.OrderId)
.LastOrDefault().ToList();
Entity Framework can't translate LastOrDefault, but it can handle Contains with sub-queries, so lookup the OrderId as a query and filter the orders by that:
// apptId is passed in, not the order, so get the related order id
var orderId = model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId);
// see if more than one appt is associated to the order
var apptOrders = model.getMyData
.Where(a => orderId.Contains(a.OrderId))
.Select(a => a.ApptId);
It seems like this is all you need:
var apptOrders =
model
.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => new { y.OrderId, y.AppointmentsId });
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();
I have two tables People and Ordersand a many-to-many relationship between the two using PeopleOrders.
Each order is associated with two people: Client and Salesman.
I have the following query:
var query = db.People
.Where(u => u.Description.Equals("Client"))
.Select(u => new {u.Id, OrderId = u.Orders.Select(p => p.Id))
})
.ToList();
This returns a json like this:
[{"Id":1,"OrderId":[2]},{"Id":9,"OrderId":[10,11,12,13]},{"Id":14,"OrderId":[14,15]}]
The ClientID and an array of orders.
I need to invert. Orders can't be an array.
So I need OrderID associated with the ClientID. Something like this:
[{"OrderId":2,"Id":1},{"OrderId":10,"Id":9},{"OrderId":11,"Id":9},{"OrderId":12,"Id":9},{"OrderId":13,"Id":9}]
The query would be something like:
var query = db.Orders
But I need to subquery the People table, so it return only Client; otherwise, it will return a array of People like:
{"OrderId":2,"Id":[1,10]}
Thank you in advance.
Use SelectMany:
var query = db.People
.Where(u => u.Description.Equals("Client"))
.SelectMany(u => u.Orders.Select(p => new {u.Id, p.OrderId}))
.ToList();
You could try something like this (using SelectMany, in order you flatten the projection of your data):
var query = db.People
.Where(person => person.Description.Equals("Client"))
.Select(person => new
{
PersonOrders = person.Orders
.Select(order => new
{
PersonId = person.Id,
OrderId = order.Id))
})
})
.SelectMany(x=>x.PersonOrders)
.ToList();
I know LINQ doesn't support two diff contexts in a standard 'join'.
Having said that, what I'm trying to do is, pull together a list of, shall we say, 'employees', from a 'user' and 'contact' contexts.
(These are edmx's that are from an old project, that I'm not about to mess with.)
Thing is, 'users' is WHO I want to get, but their demographics reside inside the 'contacts'. Here's the two current LINQ's:
var users = _pets_dc.Users
.Select(p => p)
.Where(x => x.Active)
.ToList();
var contacts = _poems_dc.Contacts
.Select(p => p)
.Where(x => x.Active)
.ToList();
I need contacts where 'user.Contact_GUID' equals 'contacts.Contact_GUID'.
I have tried:
var query = contacts
.Where(x => x.Contact_GUID == users
.Select(y => y.Contact_GUID)
.FirstOrDefault());
to no avail... this only brings back one contact, but won't work without .FirstOrDefault(). Any ideas?
If you are using Contact_GUID in both tables if you have FK in users table try using first query with include
var users = _pets_dc.Users.Include("Contacts")
.Where(x => x.Active)
.ToList();
you can try the following anyway:
var joined = from list1 in users
join list2 in contacts
on list1.Contact_GUID equals list2.Contact_GUID
select new { list1, list2 };
ref : https://stackoverflow.com/a/2724018/1166597
You can use below code:
var result = users.Select(e => contacts.Where(x => x.Contact_GUID == e.Contact_GUID));
Joining is one of the option that would work here, but you can modify your current solution as follows:
var query = contacts
.Where(x => users
.Select(y => y.Contact_GUID).Contains(x.Contact_GUID)
).FirstOrDefault());
Contains will check the Guid in a given list, in original solution you are comparing Guid with List<Guid>, which would fail
Option 1:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new Employee() { User = person, Demographic = employee.Demographic };
var employees = query.ToList();
Option 2:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new { person.FirstName, person.LastName, employee.Demographic };
var employees = query.ToList();