In a Linq projection for an EF entity, I am able to select only properties which are required.
In the code below ex questions. Now question has navigation property as options.
I want to select only option id and option title as nested property
If I write
options.ToList()
it will work with all properties.
I want only Options.ID and Options.Title to be included
var query = from c in context.Sec_Questions.AsNoTracking()
where c.IsActive == true
select new
{ c.ID, c.QuestionType,
c.Title, c.ControlName,
c.IsNumberOnly,
c.Maxlenghth,
options = c.Options.ToList(),
c.IsMultiple,
c.ControlID,
c.HelpText,
c.IsRequired };
var questions = query.ToList();
But this code doesn't work
var query = from c in context.Sec_Questions.AsNoTracking()
where c.IsActive == true
select new
{ c.ID, c.QuestionType,
c.Title, c.ControlName,
c.IsNumberOnly,
c.Maxlenghth,
options = new { c.Options.ID, c.options.Title },
c.IsMultiple,
c.ControlID,
c.HelpText,
c.IsRequired };
var questions = query.ToList();
From this c.Options.ToList() I understand that Options is a collection. So what you should do is use .Select to project a new object containing just those two properties:
var query = from c in context.Sec_Questions
where c.IsActive == true
select new {
c.ID,
c.QuestionType,
c.Title,
c.ControlName,
c.IsNumberOnly,
c.Maxlenghth,
Options = c.Options.Select(o => new { o.ID, o.Title }),
c.IsMultiple,
c.ControlID,
c.HelpText,
c.IsRequired };
Related
I'm a little bit stuck, I took an new project but there is so timeout issue due to queries.
I don't know the syntax in linq to improve one querie even if i tried multiple times.
The query is :
var contactslist = (User as CustomPrincipal).contacts;
var contacts = from m in db.ADDR_DEST.toList()
from n in contactslist
where m.ADDR_COUNTRY == n.country && m.ADDR_TPL_TYPE == n.tpl_type
select m;
But I want to dosen't launch this query before that i had different parametre so i remove the .toList() for adding some condition with
contacts.where(..);
And then I would like launch my query but i got an error with the type which must be an list<> but in this case it's a Iqueryable.
Can you help me please?
Is there an other way to launch this query after I do all my settings?
You can do something like that:
db.ADDR_DEST.Join(contactslist,
addr => new { country = addr.ADDR_COUNTRY, type = addr.ADDR_TPL_TYPE },
cont => new { country = cont.country, type = cont.tpl_type },
(addr, cont) => addr)
.ToList();
Then, if you want to choose the contactlist that meet certain requirements:
db.ADDR_DEST.Join(contactslist.Where(...).ToList(),
addr => new { country = addr.ADDR_COUNTRY, type = addr.ADDR_TPL_TYPE },
cont => new { country = cont.country, type = cont.tpl_type },
(addr, cont) => addr)
.ToList();
I hope you find it useful
Try (not tested):
var contacts = db.ADDR_DEST.Where(m => m.COUNTRY == contactslist.country
&& m.ADDR_TPL_TYPE == contactslist.tpl_type)
.ToList();
If contactslist is a list then try the following
var contacts = (from addr in db.ADDR_DEST
join cl in contactslist on
new {addr.COUNTRY, addr.ADDR_TPL_TYPE} equals new {cl.country, cl.tpl_type}
select new {addr})
.ToList();
The Linq join is easier to understand than its lambda equivalent!
There are some good examples here
I have a very simple SQL
SELECT s.shop_code
,SUM(im.amt) sum_amt
,s.cell_no#1 shop_cell
FROM tb_sn_so_wt_mst im
,tb_cm_shop_inf s
WHERE im.shop_code = s.shop_code
GROUP BY s.shop_code, s.cell_no#1)
then i try to code linq
var listResult = from warrantyMaster in listWarrantyMasters2.Records
join shopInfo in listShopInfos
on warrantyMaster.ShopCode equals shopInfo.ShopCode
i don't know group by shop code and cell no and sum atm, any one help me out of this problem
The group by syntax with some examples is explained here group clause (C# Reference) and related links.
Here is the direct translation of your SQL query (of course the field names are just my guess since you didn't provide your classes):
var query = from im in listWarrantyMasters2.Records
join s in listShopInfos
on im.ShopCode equals s.ShopCode
group im by new { s.ShopCode, s.CellNo } into g
select new
{
g.Key.ShopCode,
g.Key.CellNo,
SumAmt = g.Sum(e => e.Amt)
};
You can try this code:
var results = from warrantyMaster in listWarrantyMasters2.Records
from shopInfo in listShopInfos
.Where(mapping => mapping.ShopCode == warrantyMaster.ShopCode )
.select new
{
ShopCode = warrantyMaster.ShopCode,
ATM = listWarrantyMasters2.ATM,
ShellNo = shopInfo.ShellNo
}
.GroupBy(x=> new { x.ShopCode, x.ShellNo })
.Select(x=>
new{
ShopCode = x.Key.ShopCode,
ShellNo = x.Key.ShellNo,
SumATM = x.Sum(item=>item.ATM)
});
I'm trying to use LINQ to CRM to get some data in a parent/child format. It's a One to Many and I don't want the Child records flattening with the Parent. Firstly is what I'm asking possible?
I do not have navigation properties and there will be many parents returned, in turn each parent will have many children.
I'm trying to avoid multiple queries, just fetching it in 1.
So I'm after:
So the parent has many Children and the children have some other lookup properties in other tables 1 to 1.
Parent
--Child + other info
--Child + other info
Parent
--Child + other info
Parent
--Child + other info
--Child + other info
--Child + other info
etc
I've tried getting the Details as a IQueryable first, then using that joined on the header:
var detailsOnly = (from det in db.details
join inc in db.Incidents on det.detOtherId equals inc.incidentid into incidentsLo
from subInc in incidentsLo.DefaultIfEmpty()
join cli in db.Accounts on subInc.accountid equals cli.accountid into accountsLo
from subCli in accountsLo.DefaultIfEmpty()
select new
{
det,
AccName = subAcc.name,
AccRef = subAcc.accountnumber,
IncidentTicketNumber = subInc.ticketnumber,
IncidentKeyDescription = subInc.title,
IncidentMainContact = subInc.maincontactname
});
var query = from head in db.headers
where head.IsDone == isdone & head.type == typeId & head.accountid == AccountId
select new MyHeader(head)
{
MyDetails = detailsOnly.Where(md => md.det.detOtherId == head.headOtherId)
.Select(d => new MyDetail(d.det)
{
AccName = d.AccName,
AccRef = d.AccRef,
IncidentTicketNumber = d.IncidentTicketNumber,
IncidentKeyDescription = d.IncidentKeyDescription,
IncidentMainContact = d.IncidentMainContact
}).ToList()
};
var result = query.ToList();
It doesn't look like this is getting a real answer, so the best I can say is to execute the details collecting part, group it, then select the other parts from that.
var detailsOnly = (from det in db.details
join inc in db.Incidents on det.detOtherId equals inc.incidentid into incidentsLo
from subInc in incidentsLo.DefaultIfEmpty()
join cli in db.Accounts on subInc.accountid equals cli.accountid into accountsLo
from subCli in accountsLo.DefaultIfEmpty()
select new MyDetail(det)
{
AccName = subAcc.name,
AccRef = subAcc.accountnumber,
IncidentTicketNumber = subInc.ticketnumber,
IncidentKeyDescription = subInc.title,
IncidentMainContact = subInc.maincontactname
}).ToArray();
var groupedDetails = detailsOnly.GroupBy(c => c.det.detOtherId);
var query = db.headers.Where(head => head.IsDone == isdone
&& head.type == typeId
&& head.accountid == AccountId);
var result = query.Join(groupedDetails, c => c.headOtherId, c => c.Key, (a, b) => new MyHeader(a) { MyDetails = b })).ToList();
I could be way off on that, but you see the gist. I don't think it's the best way, but I don't have any experience with LINQ-to-CRM so I don't know. Something like this should work, though. Better than nothing. There might also be syntax errors, because this hasn't been tested.
from component in Materials.OfType<Container>().Where(m => m.Active)
join segmentFinanceRating in segmentFinanceRatingView on component.Id equals segmentFinanceRating.MaterialId into segmentFinanceRatingGroup
from segmentFinanceRatingWithDefault in segmentFinanceRatingGroup.DefaultIfEmpty()
select new
{
id = component.Id,
name = component.Name,
subType = component.SubType,
size = component.Size,
MaterialIds = component.Materials.Select(x => x.Id),
BrandNames = component.Brands.Select(x => x.Name),
SegmentRatings = segmentFinanceRatingWithDefault
}
I have the above LINQ to Entities query that has a LEFT JOIN to get rating values for 1 or more segments for a given component.
The segmentFinanceRating entity has the properties, { MaterialId, SegmentId, Rating, LowRated }
At the moment the results are not grouped to the relevant component, i.e. the SegmentRatings property is not a single collection of segmentFinanceRating objects, instead I have multiple data rows with 1 segmentFinanceRating object in each.
I have seen some examples of using group x by y into z but I couldn't get it working, possibly due to some of the collections on the component that I need too, I'm not sure.
Any help would be appreciated on how to do this, thanks.
GroupBy in List doesn't work for you?
var list = (from component in Materials.OfType<Container>().Where(m => m.Active)
join segmentFinanceRating in segmentFinanceRatingView on component.Id equals segmentFinanceRating.MaterialId into segmentFinanceRatingGroup
from segmentFinanceRatingWithDefault in segmentFinanceRatingGroup.DefaultIfEmpty()
select new
{
id = component.Id,
name = component.Name,
subType = component.SubType,
size = component.Size,
MaterialIds = component.Materials.Select(x => x.Id),
BrandNames = component.Brands.Select(x => x.Name),
SegmentRatings = segmentFinanceRatingWithDefault
}).ToList().GroupBy(s=> s.SegmentRatings);
In this case it's much easier to do the join in the anonymous type:
from component in Materials.OfType<Container>().Where(m => m.Active)
select new
{
id = component.Id,
name = component.Name,
subType = component.SubType,
size = component.Size,
MaterialIds = component.Materials.Select(x => x.Id),
BrandNames = component.Brands.Select(x => x.Name),
SegmentRatings = (from segmentFinanceRating in segmentFinanceRatingView
where segmentFinanceRating.MaterialId == component.Id
select segmentFinanceRating)
}
You will have an empty collection of SegmentRatings when there are none for a specific component, giving the same effect as outer join.
I'm trying to get the union of these two queries but keep getting the following error:
'System.Linq.IQueryable<AnonymousType#1>' does not contain a definition for 'Union' and the best extension method overload 'System.Linq.ParallelEnumerable.Union<TSource>(System.Linq.ParallelQuery<TSource>, System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments
The linq queries look like this:
var g = from p in context.APP_PROD_COMP_tbl
where p.FAM_MFG == fam_mfg
group p by new
{
a_B_G = p.B_G,
a_MFG = p.MFG,
a_PRODUCT_FAM = p.PRODUCT_FAM,
};
var q = from p in context.APP_COMP_tbl
where p.FAM_MFG == fam_mfg
group p by new
{
a_B_G = p.a_B_G,
a_MFG = p.a_MFG,
a_PRODUCT_FAM = p.a_PRODUCT_FAM,
};
var data = q.Union(g);
I've tried using IEnumerable around the queries, but it still didn't work. Not really sure where I'm going wrong at this point, although admittedly LINQ isn't something I've had a ton of exposure to.
Update:
So I've gone in a slightly different direction from what I posted earlier. After doing more research, the group by statements were from old code and no longer needed for the intended purpose. I changed those to select new statements and had no further issue with the union.
I think that your problem here is type mismatch: g is of type IGrouping<AnonymousType#1, APP_PROD_COMP_tbl> and q is of type IGrouping<AnonymousType#1, APP_COMP_tbl>; this is why Union gives you the error.
I am not really sure what you are trying to Union (keys of the groups or groups of data themselves) but the solution would be:
If you want to union group keys, select the keys of your groups
var data = g.Select(x => x.Key).Union(q.Select(x => x.Key));
If you want to union the groups themselves then you need to project each element from both sequences into a common type, perform the grouping and then union the groups
var g = context.APP_PROD_COMP_tbl
.Where(p => p.FAM_MFG == fam_mfg)
.Select(ToCommonType)
.GroupBy(p => new
{
a_B_G = p.B_G,
a_MFG = p.MFG,
a_PRODUCT_FAM = p.PRODUCT_FAM,
});
var q = context.APP_COMP_tbl
.Where(p => p.FAM_MFG == fam_mfg)
.Select(ToCommonType)
.GroupBy(p => new
{
a_B_G = p.a_B_G,
a_MFG = p.a_MFG,
a_PRODUCT_FAM = p.a_PRODUCT_FAM,
});
var data = g.Union(q);
private CommonClass ToCommonType(APP_PROD_COMP_tbl item)
{
return new CommonClass
{
};
}
private CommonClass ToCommonType(APP_COMP_tbl item)
{
return new CommonClass
{
};
}
The problem is your Anonymouse types don't match:
var a = Enumerable.Range(1, 10).Select(x => new {a = x}).AsQueryable();
var b = Enumerable.Range(1, 10).Select(x => new {b = x}).AsQueryable();
var c = a.Union(b);
This won't work because typeof a is not same as typeof b
var a = Enumerable.Range(1, 10).Select(x => new {a = x}).AsQueryable();
var b = Enumerable.Range(1, 10).Select(x => new {a = x}).AsQueryable();
var c = a.Union(b);
But this will work, because Anonymouse types are the same.
You can try selecting same anonymouse types from your collection in q and g. Read more about Union for IQueryable
Union on IQueryAble<TSource>() accepts IQueryAble<TSource> as a parameter, so collection has to be the same type.