Linq using Select and an Indexer - c#

I have the following query that runs successfully in LinqPad:
var results =
from container in Container
join containerType in ContainerType on container.ContainerType equals containerType
where containerType.ContainerTypeID == 2
select new { ContainerID = container.ContainerID, TypeID = container.ContainerTypeID};
results.Dump();
I would like to change the select to use an indexer so that the select would look something like this:
select new { ContainerID = container.ContainerID, TypeID = container.ContainerTypeID, ContainerIndex = index };
What I cannot seem to get right is the proper syntax for select to use the select indexer.
Thanks for your help.

You can't get the index with the query expression format, but there's an overload for Select that you can use in dot notation that will do it. You can stick to query expression format for the bulk of it, and then add the index in an extra select projection:
var tmp =
from container in Container
join containerType in ContainerType
on container.ContainerType equals containerType
where containerType.ContainerTypeID == 2
select new { ContainerID = container.ContainerID,
TypeID = container.ContainerTypeID};
var results = tmp.Select((x, index) => new { x.ContainerID, x.TypeID,
ContainerIndex = index });

I'm probably missing something, but if your items in Container already have property ContainerTypeID, I don't understand why you need the join. It appears to me that joining to ContainerType is not providing any extra properties that are required for this operation.
As such:
Container
.Where(c => c.ContainerTypeID==2)
.Select((c,i) => new {c.ContainerID, c.TypeID, Index = i})

Related

Linq Join query returning empty dataset

I am using below code to join two tables based on officeId field. Its retuning 0 records.
IQueryable<Usage> usages = this.context.Usage;
usages = usages.Where(usage => usage.OfficeId == officeId);
var agencyList = this.context.Agencies.ToList();
var usage = usages.ToList();
var query = usage.Join(agencyList,
r => r.OfficeId,
a => a.OfficeId,
(r, a) => new UsageAgencyApiModel () {
Id = r.Id,
Product = r.Product,
Chain = a.Chain,
Name = a.Name
}).ToList();
I have 1000+ records in agencies table and 26 records in usage table.
I am expecting 26 records as a result with chain and name colums attached to result from agency table.
Its not returning anything. I am new to .net please guide me if I am missing anything
EDIT
#Tim Schmelter's solution works fine if I get both table context while executing join. But I need to add filter on top of usage table before applying join
IQueryable<Usage> usages = this.context.Usage;
usages = usages.Where(usage => usage.OfficeId == officeId);
var query = from a in usages
// works with this.context.usages instead of usages
join u in this.context.Agencies on a.OfficeId equals u.OfficeId
select new
{
Id = a.Id,
Product = a.Product,
Chain = u.Chain,
Name = u.Name
};
return query.ToList();
Attaching screenshot here
same join query works fine with in memory data as you see below
Both ways works fine if I add in memory datasource or both datasource directly. But not working if I add filter on usages based on officeId before applying join query
One problem ist that you load all into memory first(ToList()).
With joins i prefer query syntax, it is less verbose:
var query = from a in this.context.Agencies
join u in this.context.Usage on a.OfficeId equals u.OfficeId
select new UsageAgencyApiModel()
{
Id = u.Id,
Product = u.Product,
Chain = a.Chain,
Name = a.Name
};
List<UsageAgencyApiModel> resultList = query.ToList();
Edit: You should be able to apply the Where after the Join. If you still don't get records there are no matching:
var query = from a in this.context.Agencies
join u in this.context.Usage on a.OfficeId equals u.OfficeId
where u.OfficeId == officeId
select new UsageAgencyApiModel{ ... };
The following code can help to get the output based on the ID value.
Of course, I wrote with Lambda.
var officeId = 1;
var query = context.Agencies // your starting point - table in the "from" statement
.Join(database.context.Usage, // the source table of the inner join
agency => agency.OfficeId, // Select the primary key (the first part of the "on" clause in an sql "join" statement)
usage => usage.OfficeId , // Select the foreign key (the second part of the "on" clause)
(agency, usage) => new {Agency = agency, Usage = usage }) // selection
.Where(x => x.Agency.OfficeId == id); // where statement

Linq OrderBy String Property Length Has To Be in Select List

I am attempting to order the results of a Linq query by the length of a property and then by the property itself in order to order a string as an integer but the generated SQL is not ordering as I would expect it to.
I am joining multiple tables, filtering it down, selecting a DTO out with:
query = basequery.Select(s => new HeadersDTO
{
headerid = s.Header.id,
orderno = s.Header.orderno,
customer = s.Header.customer,
dateoforder = s.Header.dateoforder,
consignee = s.Location.name,
city = s.Location.name,
state = s.Location.state
}).Distinct();
Then trying to order by s.Header.orderno
query = query.OrderByDescending(x => x.orderno.Length).ThenByDescending(x => x.orderno)
.Skip(() => offset).Take(() => criteria.per_page);
This still orders it the normal way strings are ordered with first character taking precedence.
But if I select the x.orderno.Length out into it's own property and then order by that it works e.g.
query = basequery.Select(s => new HeadersDTO
{
ordernolength = s.Header.orderno.Length <---- added this
headerid = s.Header.id,
orderno = s.Header.orderno,
customer = s.Header.customer,
dateoforder = s.Header.dateoforder,
consignee = s.Location.name,
city = s.Location.name,
state = s.Location.state
}).Distinct();
query = query.OrderByDescending(x => x.ordernolength).ThenByDescending(x => x.orderno)
.Skip(() => offset).Take(() => criteria.per_page);
Is there a way to do this where I don't have to create a new property in the select list? I can add more information if needed.
Try to create a custom Comparer using IComparer where you do the Int32 check for this field. Here is an example for this:
Use own IComparer<T> with Linq OrderBy
Hope this helps

LINQ Join: Object reference not set to an instance of an object

I have a list that are generated from Linq to SQL. For simplicity it looks like this:
var myItems = (from my in db.MyTable
select new
{
UniqueID = my.ID,
UserName = my.UserName,
CreatedOn = my.CreatedOn
}).ToList();
This list contains 4 items.
And I have another:
var grid = (from q in AnotherLinqQuery
select new
{
UniqueID = q.ID,
Department = q.Department,
Comments = q.Comments
}).ToList();
This list contains 20 items.
All the ID's in myItems appear in grid.
Now I want to join it up with a left join.
var q = from A in grid
from B in myItems.Where(x => x.UniqueID == grid.UniqueID).DefaultIfEmpty()
select new
{
UniqueID = A.UniqueID,
Department = A.Department,
CreatedOn = B.CreatedOn
}
When I execute this, I get
Object reference not set to an instance of an object.
I've also tried other joins such as
from A in grid
from B in myItems.Where(x => x.UniqueID != null && x.UniqueID == grid.UniqueID).DefaultIfEmpty()
You are not joining correctly. Try this:
var q = from A in grid
join B in myItems on A.UniqueId equals B.UniqueId into LB
from B in LB.DefaultIfEmpty()
select new
{
UniqueID = A.UniqueID,
Department = A.Department,
CreatedOn = B.CreatedOn
};
You may want to refer to the documentation for further info on joining in linq.
Since you are doing a left join instead of an inner join, there will be no items from myItems for the 16 elements that are only in grid but not in myItems.
B will be null in that cases (as DefaultIfEmpty() creates a sequence with one null element), so you have to check for null here:
var q = from A in grid
from B in myItems.Where(x => x.UniqueID == grid.UniqueID).DefaultIfEmpty()
select new
{
UniqueID = A.UniqueID,
Department = A.Department,
CreatedOn = B?.CreatedOn ?? DateTime.MinValue // or whatever default value you like
}

Avoid extra loop and could not find implementation of query pattern for source type int Select not found

How I can avoid Extra loop and construct order in the LINQ quest itself.
GetOrderListDataContext orderListDaCtx = new GetOrderListDataContext(address);
// This line showing compiler error could not find implementation of query pattern for source type int Select not found
var orderList = from order in orderListDaCtx.Base_Purchase_GetOrderListByUser_WS(request.UserGuid, request.CountryCode, request.FromDate, request.ToDate)
select order;
// Here how i can avoid this loop and construct order object in the LINQ itself above
List<Order> orders = new List<Order>();
foreach (var order in orderList)
{
orders.Add(new Order
{
OrderKey = order.OrderKey,
UserEmail = order.UserEmail,
CreatedDate = order.CreatedDate
});
}
return orders;
Do You mean this?
GetOrderListDataContext orderListDaCtx = new GetOrderListDataContext(address);
var orderList = from order in orderListDaCtx.Base_Purchase_GetOrderListByUser_WS(request.UserGuid, request.CountryCode, request.FromDate, request.ToDate)
select new Order{
OrderKey = order.OrderKey,
UserEmail = order.UserEmail,
CreatedDate = order.CreatedDate
}
return orderList.ToList();
You can just chain:
var orders = orderListDaCtx.Base_Purchase_GetOrderListByUser_WS(request.UserGuid, request.CountryCode, request.FromDate, request.ToDate)
.Select(order => new Order
{
OrderKey = order.OrderKey,
UserEmail = order.UserEmail,
CreatedDate = order.CreatedDate
})
.ToList();
return orders;
This line showing compiler error could not find implementation of
query pattern for source type int Select not found
You main problem is from your stored procedure. Refer: Linq Stored Procedure Issue- Returning an int
See LINQ Error:
Could not find an implementation of the query pattern for source type 'Your.Type'. 'Select' not found. Consider explicitly specifying the type of the range variable
It's likely that orderListDaCtx.Base_Purchase_GetOrderListByUser_WS(request.UserGuid, request.CountryCode, request.FromDate, request.ToDate) returns type 'IEnumerable', but the LINQ requires IEnumerable<T>. You have to perform explicit cast:
var orderList = from Order order in orderListDaCtx.Base_Purchase_GetOrderListByUser_WS(request.UserGuid, request.CountryCode, request.FromDate, request.ToDate)
select order;
I assume, that that Base_Purchase_GetOrderListByUser_WS returns collection of Order.

dynamic linq group by clause

I have multiple linq queries that retrieve the same data just at different grouping levels. (potentially 3 different levels). The linq query currently results in an enumerable list of a custom object. The items I don't understand or wonder if possible (to reduce redundant code):
can I make the following group by clause to be dynamic?
if so, can it dynamically populate my custom object group data when it is grouped at that level.
For instance:
var myReport_GroupProductLevel =
from r in mySum_GroupProductLevel
join pc in _myPlotCount on r.Strata equals pc.Strata
join acr in _myStrataAcres on pc.Strata equals acr.Strata
group new { r, pc, acr } by new { r.Strata, pc.Count, acr.Acres, r.GroupName, r.ProductName } into g
select new DataSummary
{
Strata = g.Key.Strata,
PlotCount = g.Key.Count,
Acres = g.Key.Acres,
ClassName = string.Empty,
GroupName = g.Key.GroupName,
ProductName = g.Key.ProductName,
TPAMEAN = g.Sum(x => x.r.TPA / x.pc.Count),
TPADEV = g.Select(x => x.r.TPA).StdDev(g.Key.Count)
};
If I wanted to group only by "GroupName" instead... I would rewrite the query. Issues I see are, if I'm grouping by a value then I need that value in the query (g.Key.GroupName); but since I'm creating a new custom object the other non-grouped values such as "ClassName" require a value (I used string.Empty above, but that is static).
Thanks for any insight...
if anyone was curious, I got it to work by using a conditional statement... since grouping by empty will make it collapse.
var mySum_ClassGroupProductLevel =
from s in ReportData.myStands
join p in ReportData.myPlots on s.ID equals p.StandID
join t in ReportData.myTrees on p.ID equals t.PlotID
group t by new { s.Strata, p.ID,
ClassName = useClassName ? t.ClassName : string.Empty,
GroupName = useGroupName ? t.GroupName : string.Empty,
ProductName = useProductName ? t.ProductName : string.Empty }
into g
select new
{}

Categories

Resources