Multiple Left Outer Joins with Collections and EF4 - linq

I have a Linq statement using EF4
var q = from a in FunctionA
from b in FunctionB.Where(a=>a.Id== b.Id).DefaultIfEmpty()
from c in FunctionC.Where(c=>c.Id== b.Id).DefaultIfEmpty()
select a;
where FunctionA,FunctionB and FunctionC returns Collections.
For some data conditions, i am getting a null exception, since the value of b in "from b in FunctionB.Where(a=> a.Id== b.Id).DefaultIfEmpty()" is null sometimes and then the statement "from c in FunctionC.Where(c=>c.Id== b.Id).DefaultIfEmpty()" blows up since b is null.
What would be correct way to do an outer join here ? please help !
Thanks !

Your Where syntax looks incorrect and I think you are actually using linq-to-objects, but all you need to do is add a condition to check Where b is not null
Edit - Based on your comments you want to do this
var q = from a in FunctionA
from b in FunctionB.Where(x => a.Id == x.Id).DefaultIfEmpty()
from c in FunctionC.Where(x => b != null && b.Id== x.Id).DefaultIfEmpty()
select a;

Related

How to solve this Error in Linq : Operator '!=' cannot be applied to operands of type 'int' and 'System.Linq.IQueryable<int>'

var ll = from a in db.EmployeeMasters
where a.EmployeeID != (from d in db.EmployeeMasters
join c in db.PerformanceDetails on d.EmployeeID equals c.EmployeeID
join z in db.ProjectMasters on c.ProjectID equals z.ProjectID
into ss
from z in ss.DefaultIfEmpty()
where z.ProjectName == name || z.ProjectName == name1
select d.EmployeeID)
select a.EmployeeName;
It returns an error messages like below
Operator '!=' cannot be applied to operands of type 'int' and 'System.Linq.IQueryable'
I want to add this Linq query in http post method to view output in postman
Anyone Please help me to solve this
Actual question is select employees who are not part of 2 projects like (CRM, Automation)
Part of both project employees are in another project but some of the employees not in any projects
My Entity Framework Data Model is shown here:
name and name1 are given parameters for project names
You're making this much harder than necessary. In the first place, you should use these navigation properties EF kindly creates for you, instead of using verbose and error-prone join statements. Doing that, it's much easier to write a greatly simplified predicate:
var ll = from a in db.EmployeeMasters
where !a.PerformanceDetails
.Any(pd => pd.ProjectMaster.ProjectName == name
|| pd.ProjectMaster.ProjectName == name1)
select a.EmployeeName;
This is a different query --it translates into EXISTS-- but the result is the same and the query plan may even be better. Also, it's much easier to add more predicates to it later, if necessary.
Your question isn't really clear, but the error is pretty clear, you cannot compare type int and System.Linq.IQueryable<int>.
I assume your want something like this :
var ll = from a in db.EmployeeMasters
where !(from d in db.EmployeeMasters
join c in db.PerformanceDetails on d.EmployeeID equals c.EmployeeID
join z in db.ProjectMasters on c.ProjectID equals z.ProjectID
into ss
from z in ss.DefaultIfEmpty()
where z.ProjectName == name || z.ProjectName == name1
select d.EmployeeID).Contains(a.EmployeeID)
select a.EmployeeName;
Here we're looking for EmployeeIDs that do not appear in your query result.
int[] EmployeeIDs = (from em in db.EmployeeMasters
join pd in db.PerformanceDetails on em.EmployeeID equals pd.EmployeeID into pdRes
from pdResult in pdRes.DefaultIfEmpty()
join pm in db.ProjectMasters on pdResult.ProjectID equals pm.ProjectID into pmRes
from pmResult in pmRes.DefaultIfEmpty()
where (pmResult.ProjectName == "Automation" || pmResult.ProjectName == "CRM Customer")
select em.EmployeeID
).Distinct().ToArray();
var empResult = (from em in db.EmployeeMasters
where !EmployeeIDs.Contains(em.EmployeeID)
select new
{
EmployeeName = em.EmployeeName
}).ToList();

How to perform LINQ left outer join using method syntax?

Microsoft has this help page for performing a left outer join, however it's in linq query syntax. What's the equivalent to this, using method syntax?
http://msdn.microsoft.com/en-us/library/bb397895.aspx
For example, I have two enumerables:
class TA {string Name{get;}}
class TB {string Name{get;}}
Enumerable<TA> A;
Enumerable<TB> B;
The result I want is this:
var joined =
A.Select(a => new
{ left = a,
right = B.FirstOrDefault(b => b.Name == a.Name)
});
This gives me what I need with just select and (effectively) a nested select. Perhaps this isn't an actual left outer join...
I've used something like
var q = (from a in db.Item1Set
from b in db.Item2Set.Where(i2 => i2.Item1Id == a.Id).DefaultIfEmpty());

LINQ join multiple conditions

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.

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.

SubSonic3 linq problem

I have this query:
var rights = from gu in db.GroupUsers
join g in db.Groups on gu.GroupId equals g.GroupId
join gr in db.GroupRights on g.GroupId equals gr.GroupId
join r in db.Rights on gr.RightId equals r.RightId
where gu.UserId == userId && g.IsDeleted == false
select r;
It gets translated to:
SELECT [t0].[Name] AS Name1, [t0].[RightId] AS RightId1
FROM [dbo].[GroupUsers] AS t1
INNER JOIN [dbo].[Groups] AS t2
ON ([t1].[GroupId] = [t2].[GroupId])
INNER JOIN [dbo].[GroupRights] AS t3
ON ([t2].[GroupId] = [t3].[GroupId])
INNER JOIN [dbo].[Rights] AS t0
ON ([t3].[RightId] = [t0].[RightId])
WHERE (([t1].[UserId] = 3345) AND ([t2].[IsDeleted] = 0))
This is still ok, but in .NET my SubSonic objects are all empty. So the query returns 15 objects, but Name and RightId are an empty string and -1.
Can this have anything to do with the fact that Name is returned as Name1 and RightId is returned as RightId1?
I'll have a look into the source code of SubSonic3 to find something.
SubSonic3 Source Code: the query does get translated to the sql above. Because of the Name1 and RightId1, the Load in Database.cs doesn't work properly. The line :
currentProp = cachedProps.SingleOrDefault
(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase));
doesn't find the currentProp because the currentProp is Name (and RightId) and not Name1 and RightId1. Well, fixing this won't be for today. Maybe someone from SubSonic3 can have a look at this, because it's pretty annoying. I could write a sort of hack into the source code, but it won't be pretty. I guess the translation should be cleaned up so that Name1 and RightId1 are translated back to Name and RightId.
In TSqlFormatter.cs there's next line that adds these AS strings
(in method :
protected override Expression VisitSelect(SelectExpression select)
{
...
if (!string.IsNullOrEmpty(column.Name) && (c == null || c.Name != column.Name))
{
sb.Append(" AS ");
sb.Append(column.Name);
}
...
}
If I put the two Appends in comment, then my linq query does work and I do get the right data. But I guess those two lines are there for a reason, but what reason? In which usecase are the two lines necessary?

Resources