LINQ join multiple conditions - linq

I have formed the following LINQ query, but it gives error
mcc_season is not an attribute in mcc_product
How do I form the query where I have 2 WHERE conditions and both from different entities in the join
var guestCardProduct =
(from c in CrmOrgServiceContext.mcc_productpriceSet
join d in CrmOrgServiceContext.mcc_productSet
on c.mcc_product.Id equals d.mcc_productId
where d.mcc_producttype.Value == (int)mcc_product.mcc_producttypeOptionSet.GuestCard
&& c.mcc_season.Id == seasonId
select new
{
d.mcc_productId,
c.mcc_price
}).FirstOrDefault();

You might be able to re-write it as follows:
var guestCardProduct =
(from c in CrmOrgServiceContext.mcc_productpriceSet
where c.mcc_season.Id == seasonId
join d in CrmOrgServiceContext.mcc_productSet
on c.mcc_product.Id equals d.mcc_productId
where d.mcc_producttype.Value == (int)c.mcc_product.mcc_producttypeOptionSet.GuestCard
select new
{
d.mcc_productId,
c.mcc_price
}).FirstOrDefault();
We're assuming here that there are 1 - 0..1 relationships between mcc_productpriceSet and both mcc_season and mcc_product and also a 1 - 0..1 relationship between mcc_product and mcc_producttypeOptionSet. If you have 1-n relationships between any of these, then you are going to have to work through those relationships rather than dotting into the single property because you will have collections of child objects rather than a single child object. You may find it helpful to break your query into smaller pieces to narrow down the source of the problem.

Related

What tools are there that help build expression trees for dynamic LINQ queries?

My project needs to let users build their own dynamic queries. From what I've read, Expression Trees are the way to go. However the syntax is rather complicated.
I envision having a GUI where users would be able to check tables, select columns, specify parameters,etc and then build a string such as:
var myQuery =
from P in context.Projects
join UA in context.UserAttributes on P.ProjectID equals UA.ProjectID
join UBA in context.UserBooleanAttributes on UA.UserAttributeID equals UBA.UserAttributeID
join U in context.Users on UBA.UserID equals U.UserID
where P.ProjectID == 1
where UBA.Value == true
where (UA.UserAttributeID == 1 || UA.UserAttributeID == 2)
select new { uba = U };
And store that in a queries table. To process the query, I was hoping there is some library out there that will magically do something like:
var result = magic(str);
foreach(var user in result)
Foo(user.Email);
In this example I know that all my queries would return Users, but for other queries I would probably have to use reflection or in another column specify the expected type in results.
I found one project called LinqTextQueryBuilder which looks interesting, but I wanted to see if there are other alternatives.

LINQ query complex join problem

So I was trying to convert a SQL into LINQ query
the logic is:
JOIN SalesPeriod SP1
ON
SP1.SalesPeriodId = SE1.SalesPeriodId AND SP1.SalePeriodId = .....(XML stuff)
but it keeps complaining the types on both sides of equals statement don't match
Any ideas?
Note: I declared b and d because it doesn't accept anonymous type members
and I tested two equal conditions separately and they both work
thanks
join SP1 in fentities.SalesPeriods
on new { SE1.SalesPeriodId, b = XDocument.Load(MI.Body).Element("ns:Transfer").Element("ns:ReceivedBy").Element("ns:Id").FirstNode.ToString() }
equals new { SP1.SalesPeriodId, d = SP1.SalesPeriodId.ToString() }
Simple, they're not the same (compatible) types. The first key has a SalesPeriodId of type whatever, and b of type string. The second key has a SalesPeriodId of type whatever (probably the same as the first's), and d of type string. You can't compare these to eachother. It must have the same properties of the same types declared in the same order. Just pick one of the names b or d and use that name.
...
join SP1 in fentities.SalesPeriods
on new { SE1.SalesPeriodId, b = XDocument.Load(MI.Body).Element("ns:Transfer").Element("ns:ReceivedBy").Element("ns:Id").FirstNode.ToString() }
equals new { SP1.SalesPeriodId, b = SP1.SalesPeriodId.ToString() }
Your two anonymous types do not match, b & d to be specific.. try aligning the signatures..
join SP1 in fentities.SalesPeriods
on new { SE1.SalesPeriodId, b = XDocument.Load(MI.Body).Element("ns:Transfer").Element("ns:ReceivedBy").Element("ns:Id").FirstNode.ToString() }
equals new { SP1.SalesPeriodId, b = SP1.SalesPeriodId.ToString() }
In that example both anonymous objects will have the same property definitions (SalesPeriodId and b)
Don't stuck on putting complete join condition into 'ON' clause. Split condition on two parts, put one of them into 'ON' clause and another into 'WHERE' clause.
join SP1 in fentities.SalesPeriods
on SE1.SalesPeriodId equals SP1.SalesPeriodId
where XDocument.Load(MI.Body).Element("ns:Transfer").Element("ns:ReceivedBy").Element("ns:Id").FirstNode.ToString() == SP1.SalesPeriodId.ToString()

Greater Than Condition in Linq Join

I had tried to join two table conditionally but it is giving me syntax error. I tried to find solution in the net but i cannot find how to do conditional join with condition. The only other alternative is to get the value first from one table and make a query again.
I just want to confirm if there is any other way to do conditional join with linq.
Here is my code, I am trying to find all position that is equal or lower than me. Basically I want to get my peers and subordinates.
from e in entity.M_Employee
join p in entity.M_Position on e.PostionId >= p.PositionId
select p;
You can't do that with a LINQ joins - LINQ only supports equijoins. However, you can do this:
var query = from e in entity.M_Employee
from p in entity.M_Position
where e.PostionId >= p.PositionId
select p;
Or a slightly alternative but equivalent approach:
var query = entity.M_Employee
.SelectMany(e => entity.M_Position
.Where(p => e.PostionId >= p.PositionId));
Following:
from e in entity.M_Employee
from p in entity.M_Position.Where(p => e.PostionId >= p.PositionId)
select p;
will produce exactly the same SQL you are after (INNER JOIN Position P ON E..PostionId >= P.PositionId).
var currentDetails = from c in customers
group c by new { c.Name, c.Authed } into g
where g.Key.Authed == "True"
select g.OrderByDescending(t => t.EffectiveDate).First();
var currentAndUnauthorised = (from c in customers
join cd in currentDetails
on c.Name equals cd.Name
where c.EffectiveDate >= cd.EffectiveDate
select c).OrderBy(o => o.CoverId).ThenBy(o => o.EffectiveDate);
If you have a table of historic detail changes including authorisation status and effective date. The first query finds each customers current details and the second query adds all subsequent unauthorised detail changes in the table.
Hope this is helpful as it took me some time and help to get too.

Aggregate functions with a left outer join in LINQ to Entities

I've been looking through related LINQ questions here trying to figure this one out, but I'm having some trouble converting a SQL query of mine to the equivalent LINQ to Entities version.
select companies.CommpanyName,
job.Position,
count(offers.jobID) As Offered,
job.Openings,
job.Filled
from jobs
left outer join offers on jobs.ID = offers.JobID
join membership.dbo.individuals on jobs.UserID = individuals.ID
join membership.dbo.companies on individuals.CompanyID = companies.ID
where jobs.Hidden = 0
group by offers.JobID,
companies.CommpanyName,
job.Position,
job.Openings,
job.Filled
I've done left outer joins in LINQ before similar to this example but I'm not sure how to combine the count and group statements with this to get the desired result:
CompanyName Position Offered Openings Filled
1 Exmaple Co. Job X 0 2 0
2 Example Co. Job Y 4 6 3
3 Test Co. Job Z 1 1 1
The query is further complicated by the fact that it needs to utilize two separate data contexts. I apologize for the lack of example code, but I'm really not sure how to start this, my LINQ-fu is still weak.
Update:
This is the solution I arrived at with Craig's help, had to use LINQ to Objects because of the unfortunate multiple context setup, JobWithOfferCounts is not an entity object:
IEnumerable<Job> t = context1.JobSet.Include("Offers").Include("Contacts").Where(j => j.Hidden == false);
IEnumerable <JobWithOfferCounts> r = (from j in t
join i in context2.IndividualSet on j.UserID equals i.ID
join c in context2.CompanySet on i.CompanyID equals c.ID
select new JobWithOfferCounts()
{
JobObject = j,
CompanyID = Convert.ToInt32(c.ID),
CompanyName = c.HostName,
OfferCount = j.offers.Count(o => o.Rejected == false),
FilledCount = j.offers.Count(o => o.Accepted == true),
PendingCount = j.offers.Count(o => o.Accepted == false && o.Rejected == false)
});
return r;
I can't see why you have individuals in your query, or why you group by offers.JobID when it (unlike jobs.JobId) could be null, but here's a first stab:
var q = from c in Context.Companies
from i in c.Individuals
from j in i.Jobs
where j.Hidden == 0
select new
{
CompanyName = c.CompanyName,
Position = j.Position,
Offered = j.Offers.Count(),
Openings = j.Openings,
Filled = j.Filled
};
It's rarely correct to use join in LINQ to Entities or LINQ to SQL.

How to write linq to get data from different tables?

Suppose I have 3 tables: A(aid, ...), B(bid, ...) Relationship(aid, bid, ...)
Then I have a aid as parameter, I want to get the result from b. If use SQL, will be like
select b.* from B join Relationship on b.bid = Relationship.bid
where relationship.aid = aid_param
how to write linq with same result as above SQL. (the foreign key was not created correctly in this case)?
Assuming that you've used the designer to add your tables to the LINQ data context and you have either foreign key relationships defined in the database or have hand-coded the associations in the designer, you should simply be able to reference the B table and it's EntitySet of Relationship properties, filtered by your parameter, and check if there are any matches.
var relationships = db.B.Any( b => b.Relationships.Where( r => r.aid == aid_param ) );
var bQuery = from r in MyContext.Relationship
where r.aid == aid_param
select r.B;
If you don't have a relationship set in the model, then u can:
var bQuery = from b in myContext.B
where myContext.Relationship
.Any( r => r.aid == aid_param && b.bid == r.bid)
select b;
var output =
from b
from Relationship
where (b.bid = Relationship.bid,
relationship.aid = aid_param)

Resources