Linq one-to-many Union - c#

I'm developing a MVC web application using asp.net C# and VS2012 Express.
I have a table (Organizations) with one-to-many relationships with two other tables (Comments and Proposals). All three tables contain an OrganizationID field to maintain the relationships. All three tables have an AddedBy string field.
I want to find all Organizations where either the Organization.AddedBy="Joe" or Comments.AddedBy="Joe" or Proposals.AddedBy="Joe".
These queries do a join, but I'm looking for a union that contains only the Organizations' fields.
// Find organizations created by this person.
IQueryable<Organization> org = from m in context.Organizations
where m.AddedBy.Equals("Joe")
select m;
// Find Comments created by this person.
IQueryable<Comment> comment = from m in context.Comments
where m.AddedBy.Equals("Joe")
select m;
// Join our two queries.
IQueryable<Comment> organizations = (from item in org
join c in comment on item.OrganizationID equals c.OrganizationID
select item).Distinct();
// Find Proposals created by this person.
IQueryable<Proposal> proposal = from m in context.Proposals
where m.AddedBy.Equals("Joe")
select m;
// Join our two queries.
organizations = (from item in organizations
join c in proposal on item.OrganizationID equals c.OrganizationID
select item).Distinct();
Thanks for your help.

If you are using Entity Framework you can do either:
var orgs = context.Organizations
.Where(O => O.AddedBy.Equals("Joe") ||
O.Comments.Any(C => C.AddedBy.Equals("joe")) ||
O.Proposals.Any(P => P.AddedBy.Equals("joe")));
As EF maintaining the parent-child relationship with navigation properties.
Hope this will help !!

So you're looking for three different sets, all combined. Just query each of those three things and then combine them using Union:
string user = "Joe";
var addedOrganizations = context.Organizations.Where(org => org.AddedBy == user);
var orgsWithUsersComments = from org in context.Organizations
join c in context.Comments
on org.OrganizationID equals c.OrganizationID
where c.AddedBy == user
select org;
var orgsWithUsersProposals = from org in context.Organizations
join p in context.Proposals
where p.AddedBy == user
select org;
var combinedResults = addedOrganizations.Union(orgsWithUsersComments)
.Union(orgsWithUsersProposals);

Related

C# & Entity Framework : return specific columns from a 3 table join

I have a C# application where I am using Entity Framework to pull data from a database. This is the code I am executing:
var person = new List<Person>();
using (DevTestEntities db = new DevTestEntities())
{
person = (from p in db.People
join e in db.PersonEmails on p.Id equals e.Id
join t in db.PersonPhones on p.Id equals t.Id
where t.Phone == phoneNumber
select p).ToList();
}
var str = Newtonsoft.Json.JsonConvert.SerializeObject(person);
return str;
When the code runs, it fails on the select. I assume it is failing because there is a table within the database that is not part of the model. And because there is just a generic select, I assume Entity Framework is selecting all columns from all tables and doesn't know what to do with some of the columns.
What I really want to do is to be able to specify the columns that I want to return to the calling function. How do I specify what columns Entity Framework should select?
Thanks for any assistance.
EF will not fail because of tables in the DB that are not in model. It would help if you provided the error. Also, your query will result in selecting all columns from the People table but not the others.
An example answer to your question is this, it selects three columns from different tables and puts them in a new anonymous type:
var onlySomeColumns = (from p in db.People
join e in db.PersonEmails
on p.Id equals e.Id
join t in db.PersonPhones
on p.Id equals t.Id
where t.Phone == phoneNumber
select new {p.Id, e.email, t.phonenumber}).ToList();

Entity Framework Core: join two tables and get the properties I want using LINQ

I have two related tables. Then I use LINQ to query Data.
this is my code
var items = await (from a in queryable
join b in _context.TUserGrant on a.UserNo equals b.UserNo
join c in _context.TProviderInfo on a.ProviderNo equals c.ProviderNo
orderby a.BillNo
select new
{
a.BillNo,
a.NotificeBillNo,
makeName = b.UserName,
a.MakeDate,
a.ProviderNo,
c.ProviderName,
a.CheckTime,
a.CheckAddress,
a.CheckName,
a.StatusTitle,
}).ToListAsync();
My problem is that I need all the columns of the first table, which is all the values of A.
I also need some columns from table B.
I wonder if there is an easy way to get these columns.
Instead of setting them one by one in the SELECT method.
You can try this
var items = await (from a in queryable
join b in _context.TUserGrant on a.UserNo equals b.UserNo
join c in _context.TProviderInfo on a.ProviderNo equals c.ProviderNo
orderby a.BillNo
select new
{
tabA = a,
makeName = b.UserName
}).ToListAsync();

LINQ multiple joins performance optimization

I need to retrieve a list of orders records, and on the same view I have to show for each order:
how many invoices have been issued (InvoiceCount)
the total amount covered by the invoices (Invoiced)
how much has been paid for the issued invoices (Payed)
all on the same grid view.
I think it's a basic view for business management software.
Order > invoices = one-to-many
Payments are related to invoices with a look-up table PaymentsToInvoices
GridView is paged server-side, with a page-size of 50 records.
I've written the following LINQ, that it works fine, but I have some doubt that is well written in terms of performance,
especially if this query is finally translated with a couple of sub-queries, that means 50*2 queries for each request!
var orders = (from o in db.Orders
join c in db.Customers on o.CustomerID equals c.CustomerID
join os in db.OrderStatuses on o.OrderStatusID equals os.OrderStatusID
join ps in db.PaymentStatuses on o.PaymentStatusID equals ps.PaymentStatusID
join ec in db.EntryChannels on o.EntryChannelID equals ec.EntryChannelID
orderby o.InsertDate descending
where o.OrderStatusID == 2
select new
{
o.OrderID,
o.CustomerID,
o.InsertDate,
o.TotalPrice,
o.Notes,
c.FirstName,
c.LastName,
OrderStatus = os.Name,
PaymentStatus = ps.Name,
EntryChannel = ec.Name,
InvoiceCount = (db.InvoiceDetails.Where(i => i.OrderID == o.OrderID).Select(s => s.InvoiceID).Distinct().Count()),
Invoiced = (db.InvoiceDetails.Where(i => i.OrderID == o.OrderID).Select(s => s.TotalPrice).Sum()),
Payed = (from py in db.Payments
join pti in db.PaymentsToInvoices on py.PaymentID equals pti.PaymentID
join inv in db.InvoiceDetails on pti.InvoiceID equals inv.InvoiceID
where inv.OrderID==o.OrderID
select new { py.PaymentID, py.Amount }).Distinct().Select(s=>s.Amount).Sum()
});
What do you think about the last three fields? Can they be improved in some way? Do they result in performance killer sub-queries?

Linq InnerJoin 4 tables

My goal is to return a list of orders that only contain orderItems that are from a specific merchant. My current solution is to iterate through EVERY order, then through every order item and every listing. I imagine that is not the best practice, but I am having a hard time figuring out how to construct a single query to retrieve merchant specific orders.
I have 4 tables
Merchants(the id field being merchantID)
Orders(the id field is orderID)
orderItems(the id field is orderItemID, and FK listingID)
listings(the id field is listingID, and FK merchantID)
You can use .Any() to help you get to where you want:
var ordersFromMerchant = db.Orders
.Where(o => o.Items.Any(oi => oi.Listing.merchantID = 10);
I've made assumptions about the names of your navigation properties, but you should be able to adapt this if they don't match.
If you prefer the linq syntax, you can use:
var ordersFromMerchant = from o in db.Orders
join oi in db.orderItems on o.orderID equals oi.orderID
join l in db.listings on oi.listingID equals l.listingID
where l.merchantID = 10
select o;
I don't know your structure but something like this should work.
var query = from o in orders
join oi in orderItems on o.id equals io.orderID
join l in listings on oi.listingID equals l.id
where l.merchantID == merchantID
select o;

EF Query with conditional include that uses Joins

This is a follow up to another user's question. I have 5 tables
CompanyDetail
CompanyContacts FK to CompanyDetail
CompanyContactsSecurity FK to CompanyContact
UserDetail
UserGroupMembership FK to UserDetail
How do I return all companies and include the contacts in the same query? I would like to include companies that contain zero contacts.
Companies have a 1 to many association to Contacts, however not every user is permitted to see every Contact. My goal is to get a list of every Company regardless of the count of Contacts, but include contact data.
Right now I have this working query:
var userGroupsQueryable = _entities.UserGroupMembership
.Where(ug => ug.UserID == UserID)
.Select(a => a.GroupMembership);
var contactsGroupsQueryable = _entities.CompanyContactsSecurity;//.Where(c => c.CompanyID == companyID);
/// OLD Query that shows permitted contacts
/// ... I want to "use this query inside "listOfCompany"
///
//var permittedContacts= from c in userGroupsQueryable
//join p in contactsGroupsQueryable on c equals p.GroupID
//select p;
However this is inefficient when I need to get all contacts for all companies, since I use a For..Each loop and query each company individually and update my viewmodel. Question: How do I shoehorn the permittedContacts variable above and insert that into this query:
var listOfCompany = from company in _entities.CompanyDetail.Include("CompanyContacts").Include("CompanyContactsSecurity")
where company.CompanyContacts.Any(
// Insert Query here....
// b => b.CompanyContactsSecurity.Join(/*inner*/,/*OuterKey*/,/*innerKey*/,/*ResultSelector*/)
)
select company;
My attempt at doing this resulted in:
var listOfCompany = from company in _entities.CompanyDetail.Include("CompanyContacts").Include("CompanyContactsSecurity")
where company.CompanyContacts.Any(
// This is concept only... doesn't work...
from grps in userGroupsQueryable
join p in company.CompanyContactsSecurity on grps equals p.GroupID
select p
)
select company;
Perhaps something like this.
var q = from company in _entities.CompanyDetail
where
(from c in userGroupsQueryable
join p in contactsGroupsQueryable on c equals p.GroupID
where company.CompanyContacts.Any(cc => cc.pkCompanyContact == p.fkCompanyContact)
select p
).Any()
select new
{
Company = company,
Contacts = company.CompanyContacts
};
The following code queries all companies, and appends only the contacts the user is permitted to see. I don't know how efficient this is, or if there is a way to make it faster, but it works.
var userGroupsQueryable = _entities.UserGroupMembership.Where(ug => ug.UserID == UserID)
.Select(a => a.GroupMembership);
var  contactsGroupsQueryable = _entities.CompanyContactsSecurity;
var listOfCompanies =
from company in _entities.CompanyDetail
select new
{
Company = company,
Contacts = (from c in userGroupsQueryable
join p in contactsGroupsQueryable on c equals p.GroupID
where company.CompanyContacts.Any(cc => cc.CompanyID == p.CompanyID)
select p.CompanyContacts)
};

Categories