LINQ query complex join problem - linq

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()

Related

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.

LINQ .Count() not defined for int

I have the below LINQ statement, and get the error " 'int' does not contain a definition for 'Count' and no extension method 'Count' accepting a first argument of type 'int' could be found ( are you missing a using directive or assembly reference?) "
var queryFuture = from pqv in context.OrderPrintQueue_View
join od in context.Order_Details on pqv.confirmId equals od.ConfirmId
join pp in context.Product_Price on od.priceId equals pp.priceId
join p in context.Products on pp.productId equals p.ProductID
select new { p.stationId, inProc = 0, OrderLinesCount = od.recId.Count() };
od.recId.Count() is the portion that is returning an error. I'm very new to LINQ (have been using it for about 2 days) and am a novice programmer. The answers I have found all say to include the system.core assembly reference, and of course, the System.Linq using. I have all of those so I'm not sure what the deal is. I am using WPF with .NET 4, EF, and RIA services and the MVVM pattern.
recID is of type int, not IEnumerable<?>. Count() is only defined on IEnumerable<?>. You will ned a group by statement:
var queryFuture = from pqv in context.OrderPrintQueue_View
join od in context.Order_Details on pqv.confirmId equals od.ConfirmId
join pp in context.Product_Price on od.priceId equals pp.priceId
join p in context.Products on pp.productId equals p.ProductID
group od by od.recId into orders
select new { p.stationId, inProc = 0, OrderLinesCount = orders.Count() };
Note: I'm not sure of this combination of group by and join will work out, as I usually only use the method chains. You might have to adjust on the operators, however you'll need a group by in any case.
Why would you want to get the count for an integer? You are probably getting a single value back, not a collection, which it seems is what you are expecting.

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)

DataTable Query

I am new to LINQ. I am trying to find the rows that does not exists in the second data table.
report_list and benchmark both type are : DataTable. Both these datatables are being populated using OleDbCommand,OleDbDataAdapter. I am getting an error "Specified cast is not valid." in foreach ... loop. I would appreciate your help.
var result = from a in report_list.AsEnumerable()
where !(from b in benchmark.AsEnumerable()
select b.Field<int>("bench_id")
)
.Contains(a.Field<int>("BenchmarkID"))
select a;
foreach (var c in result)
{
Console.WriteLine(c.Field<string>("Name"));
}
I don't know if I understood your question. Are you trying to get the items that exists in the first table but not in the second?
var first = new string[] { "b", "c" };
var second = new string[] { "a", "c" };
//find the itens that exist in "first" but not in "second"
var q = from f in first
where !second.Contains(f)
select f;
foreach (var s in q) {
Console.WriteLine(s);
}
//Prints:
//b
I suggest you to make the inner query first, once it does not depend on the outer record.
From a in report_list
Group Join b in benchmark On a.bench_id Equals b.bench_id Into g = Group
Where g.Count = 0
Select a
Note that this is VB syntax.
My suspicion is that one of the fields you are comparing is not an integer in the database. I believe that the invalid cast exception is being thrown by one of the Field<int>() calls since that is one of the three different exceptions that this method can throw. See docs here.
Perhaps use the .Except() extension to get the set difference of the two sets?
(from b in benchmark.AsEnumerable()
select new { id = b.Field<int>("bench_id")}).Except(
from a in report_list.AsEnumerable()
select new {id = a.Field<int>("BenchmarkID")})
Not actually sure of the precise syntax, but that should work by taking the ids in benchmark, and then removing all equivalent ids in report_list, leaving only the ids that don't match. (I hope this is the order you were after...)
Note: This is also assuming that the above issue mentioned by tvanfosson isn't also a problem

Resources