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();
Related
I have two table item table and transaction table. I need to use Contain to filter for two values.
var list1= table.select(c=> new {c.ID , c.ItemID}).tolist();
var list2 = tableItem.where(x=> list1.contains(x.id ,x.itemID ));
This should work for you, may require a few tweaks since you're syntax looks a little rough.
Note the Any LINQ function I used. More details here
var list1 = table.Select(c => new { c.ID, c.ItemID }).ToList();
var list2 = tableITem.Where(x => list1.Any(a => a.ID == x.id && a.ItemID == x.itemID)).ToList();
I want to create a linq to sql query that will return a list of objects with a sublist that has been filtered.
It sounds easy but I'm not sure how to make this to work
Here the SQL Query which returns what I want:
select * from Texts t inner join Translations tt on t.TranslationId = tt.Id
inner join Pages p on tt.Id = p.TranslationId and tt.NeutralText = p.TitleNeutralTextId
where t.LanguageId = 1
Now I have to write this with linq.
What I've done so far is:
var query = this.Queryable() // Page entity
.AsNoTracking()
.Include(x => x.TitleTranslation.Texts);
return (from m in query
from l in m.TitleTranslation.Texts
where m.TitleTranslation.Texts.Any(l => l.LanguageId == 1)
select m);
But it didn't work because I got the sublist with all languages instead of language with id #1 only.
Thanks for helping,
David
Any specific reason you are writing query? Either you can use Eager Loading of EF to load all the child tables, Or below Linq statement can fetch the required result
var result = texts.Join(translations, t => t.TranslationId, tt => tt.Id, (t, tt) => new {t, tt})
.Join(pages, ttt => new { Id = ttt.tt.Id, NeutralTextId = ttt.tt.NeutralText }, p => new { Id = p.TranslationId, NeutralTextId = p.TitleNeutralTextId }, (ttt, p) => new {ttt, p})
.Where(tttt => tttt.ttt.t.LanguageId == 1);
Here replace texts, translations and pages with actual dbContext entities collection property.
I think you must try lime this. this will work for you .
This will be similar to sql query
One way to do this .
var result = from m in Texts
join Translations on Texts.TranslationId = Translation.Id
Join Pages on Translations.NeutralText = Pages.NeutralText
where Texts.LanguageId = 1
select m
There an other way to do this using entity framework
var result =
this.Queryable().AsNoTracking().Include(x=>x.Translations).Where(x=>x.LanguageId= 1)
I found the solution I wanted thanks to Hasnain Bukhari.
The solution was to start from the text table, assign the filter, include the desired Entity (Page) and put the results into memory (ToList()). Then select pages. It will give the result I want in the order I have to.
var query = textService.Queryable()
.AsNoTracking()
.Include(x => x.Translation.Pages)
.Where(x => x.LanguageId == languageId).ToList();
return query.SelectMany(x => x.Translation.Pages);
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();
So after what felt like a lot of head banging, I have this query:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First()).ToList();
widgetGrid.DataSource = widgets;
widgetGrid.DataBind();
Now that I have all the sold widgets I need to add a join, let's say for instance that I want to join the the "Owner" table on ID in Owner equals ID in Widgets and then select Owner.Name and Widget.Style
For the life of me, I seem to be getting nowhere fast... anyone?
As always... I'm deeply grateful for anyone's time in helping me clear out my cobwebs.
If I understand you correctly, you have two sequences:
a sequence of Widgets, where each widget has a property Id.
You have a sequence of Owners, where each owner has a property Id
And you want the combination of sequences and owners that have a matching Id.
By the way, probably your widget will have an ownerId or your owner will have a widgetId, but that won't influence the solution.
The join will be as follows:
var joinedTable = widgets.join(owners, // join table widgets with table owners
w => w.Id // from widgets take the Id
o => o.Id // from owners also take the Id
(widget, owner) => new // where those Ids match, take the owner and the widget
{ // and take the properties you want
Id = widget.Id,
MyXProperty = owner.X,
MyYProperty = widget.Y,
Widget = widget, // or take the complete widget and owner
Owner = owner,
});
By the way, you write "Now that I have all the sold widgets". From your piece of code I understand that each Update has a Boolean property Sold and that you want all Updates where !Sold. I'd assume you end up with items that are not sold?
What is the advantage of your predicate in the where clause. Why isn't it:
var widgets = db.Updates.Where(c => !c.Sold)
.GroupBy // etc.
You could do this:
var widgets = db.Updates
.Where(c => !c.Sold)
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).FirstOrDefault());
var result= (from w in widgets
join o in db.Owners on w.OwnerId equals o.Id
select new {o.Name, w.Style}).ToList();
you may also try:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
.Join( db.Owners,
u => u.ID,
o => o.ID,
(u, o) => new { o.Name, u.Style }).ToList();
I am trying to query a collection and child collection using EF 7. Here's the code:
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address.Where(p => p.AddressTypeID == 1))
.ThenInclude(p=> p.City)
.ToListAsync();
> Error CS1061 'IEnumerable<Address>' does not contain a definition for
> 'City' and no extension method 'City' accepting a first argument of
> type 'IEnumerable<Address>' could be found (are you missing a using
> directive or an assembly reference?) Contacts.DNX 4.5.1, Contacts.DNX
> Core 5.0
It works fine when I just use
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address)
.ThenInclude(p=> p.City)
.ToListAsync();
But this will load all the addresses for the customer where I only want the recent address for which the AddressTypeID is 1.
Any idea how to do this?
You can try anonymous projection, that will fetch translate your query into SQL.
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID)
.Select(cntct=> new
{
contact = cntct,
address = cntct.Address.Where(p => p.AddressTypeID == 1),
city = cntct.Address.Where(p => p.AddressTypeID == 1)
.Select(h=>h.City),
}.ToList();
You can't filter in Include. In any version of entity framework.
If you need to load a subset of the collection then you need to Join instead of using navigation property and filter whenever you need using Where clause
Like this (simplified, extra steps for readability):
var filteredAddresses = Addresses.Where(x=>x.AddressTypeId==1);
var customersWithAddress = Customers.Join(filteredAddresses, x=>x.Id,x=>x.CustomerId,(c,a)=> new {
Customer=c,
Address=a
});
Or if you need a single customer, assuming you have Customer navigation property in Address:
var addressWithCustomer = Addresses
.Where(x=>x.AddressTypeId==1 && x.CustomerId == customerId)
.Include(x=>x.Customer)
.Include(x=>x.City)
.Single();
A lot of times, it is better to approach queries which involve conditional nested entities, to start with the nested entity, apply the conditions to this nested fellow and then project out the parent entity, since it is always easier to reach to the parent entities from the nested enumerable ones. (many to one)
in our case, we can apply the filter out on the Address entity and then group it on the Contact entity.
var customerID = 86795;
var query = await _context.Addresses
.Where(a => a.Contact.CustomerID == customerID
&& a.Contact.RegistrationDate.Year == 2016
&& a.AddressTypeID == 1)
.Include(a => a.Contact)
.Include(a => a.City)
.GroupBy(a => a.Contact)
.Take(20) // by the way, you should apply some orderby for a predicatble Take
.ToListAsync();
and if you absolutely want a list of Contacts as the output of the above query, you can do this.
var contacts = query.Select(g =>
{
g.Key.Addresses = g.ToList();
return g.Key;
}).ToList();
// now you can work off the Contacts list, which has only specific addresses
This will basically give you a grouped list of all Contacts with CustomerID, and with those address types and registration years only. The important thing here is to iterate through the group to get the addresses, and not use the grouping.Key.Addresses navigation. (grouping.Key will be the Contact entity)
Also, I don't know if CustomerID is a primary key on the Contact entity, but if it is, it looks like you would just need a list of matching addresses for one Contact. In that case, the query would be:
var query = await _context.Addresses
.Where(a => a.Contact.CustomerID == customerID && a.AddressTypeID == 1)
.Include(a => a.Contact)
.Include(a => a.City)
.ToListAsync();
Include The Collection for Eager Load then use Any instead of Where ... to Select specific items in the child of the wanted entity.
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address.Any(p => p.AddressTypeID == 1))
.ThenInclude(p=> p.City)
.ToListAsync();