Get index in a IQueryable result - c#

I have a LINQ query:
var result = (from CC in hc.ClaimCodings
join CM in hc.ClaimCodingProcedureCodeModifierXrefs on CC.ClaimCodingID equals CM.ClaimCodingID
join PCM in hc.ProcedureCodeModifiers on CM.ProcedureCodeModifierID equals PCM.ProcedureCodeModifierID
where CC.CTCustomerSubID == custSub && CC.ClaimID == claimID
select new { PCM.ModifierCode });
EDIT
Which can return 0 to 4 items. I want to set the value of each Modifier code to a property:
public string ModCode1 { get; set; }
public string ModCode2 { get; set; }
public string ModCode3 { get; set; }
public string ModCode4 { get; set; }
Modcode1 = result.ModifierCode.getindex(0).firstordefault();
ModeCode2 = second result's ModifierCode;
etc
etc
Unless I'm approaching this completely wrong. I'm not so good with LINQ yet :(

Is this what you have in mind?
var result =
(
from CC in hc.ClaimCodings
join CM in hc.ClaimCodingProcedureCodeModifierXrefs
on CC.ClaimCodingID equals CM.ClaimCodingID
join PCM in hc.ProcedureCodeModifiers
on CM.ProcedureCodeModifierID equals PCM.ProcedureCodeModifierID
where CC.CTCustomerSubID == custSub && CC.ClaimID == claimID &&
PCM.ModifierCode != null
select PCM.ModifierCode
).ToList();
ModCode1 = result.Length > 0 ? result[0] : null;
ModCode2 = result.Length > 1 ? result[1] : null;
ModCode3 = result.Length > 2 ? result[2] : null;
ModCode4 = result.Length > 3 ? result[3] : null;
Main changes:
Added PCM.ModifierCode != null check within LINQ query.
Removed redundant anonymous type construction.
Converted LINQ query result to List<string> through ToList().
However, as BrokenGlass said, you’re probably better off storing a list.

You can call ToArray() on the results to immediately execute the query and return an array of the values. You can then assign values to the properties using the some ternary operator shorthand which checks the length of the array.
res = result.Take(4).ToArray();
Modcode1 = res.Length > 0 ? res[0] : null;
Modcode2 = res.Length > 1 ? res[1] : null;
Modcode3 = res.Length > 2 ? res[2] : null;
Modcode4 = res.Length > 3 ? res[3] : null;

Related

Is it possible to create a best fit Linq query from a list of classes?

Hi I have a function which returns the best fit of a class from a collection. I know how to replace the foreach statement using a linq query to get a new list but I would like to know if it is possible to returna single result using a linq statement that would equate to the best fit similar to the code below.
private ProductDefaults GetBestFitProductDefault(Product product,IList<ProductDefaults> defaultList, ProductDefaultsTypeEnum type)
{
ProductDefaults pdef = null;
var matches = -1;
var bestfit = matches;
foreach (var def in defaultList)
{
if(def.DefaultType == type)
{
matches = 0;
if (def.Level1Ref == product.Level1Ref)
{
matches++;
}
if (def.Level2Ref == product.Level2Ref)
{
matches++;
}
if (def.Level3Ref == product.Level3Ref)
{
matches++;
}
if (def.Level4Ref == product.Level4Ref)
{
matches++;
}
if (def.Level5Ref == product.Level5Ref)
{
matches++;
}
if (def.Level6Ref == product.Level6Ref)
{
matches++;
}
if(matches > bestfit)
{
bestfit = matches;
pdef = def;
}
}
}
return pdef;
}
After a bit of research I have come up with this Linq query to replace the code hopefully this will help someone else who may need a similar solution. The let allows me to create a new column that will calculate the bestfit or number of matches. By ordering the result descending by the bestfit I am certain that the first object will have the highest bestfit value so is the one I need. There could potentially be multiple products with the same bestfit score in this case it would be random which one was chosen but in my case this would be acceptable.
private ProductDefaults GetBestFitProductDefault(Product product, IList<ProductDefaults> defaultList, ProductDefaultsTypeEnum type)
{
ProductDefaults pdef = null;
var list =
from pd in defaultList
let bestfit = pd.Level1Ref == product.Level1Ref ? 1 : 0 +
pd.Level2Ref == product.Level2Ref ? 1 : 0 +
pd.Level3Ref == product.Level3Ref ? 1 : 0 +
pd.Level4Ref == product.Level4Ref ? 1 : 0 +
pd.Level5Ref == product.Level5Ref ? 1 : 0 +
pd.Level6Ref == product.Level6Ref ? 1 : 0
where pd.DefaultType == type
orderby bestfit descending
group pd by bestfit into pdl
select new { pdl.Key, best = pdl.ToList() };
pdef = list.First().best.FirstOrDefault();
return pdef;
}

The LINQ expression node type 'ArrayLength' is not supported in LINQ to Entities

I have implemented a linq expression to return a resultset and getting the following error
{"The LINQ expression node type 'ArrayLength' is not supported in LINQ to Entities."}
public IEnumerable<TBI.JV.Business.Objects.Asset> GetAssetsBasicBySedols(string[] sedols)
{
var priceDate = DateTime.UtcNow.Date.AddMonths(-8);
var typeList = new string[]
{
"UNIT TRUST",
"OEIC",
"INVESTMENT TRUST",
"INVESTMENT COMPANY",
"PENSION FUND",
"INSURANCE BOND",
"LISTED EQUITY",
"PREFERENCE SHARE",
"ZERO DIVIDEND PREF",
"GILT (CONVENTIONAL)",
"GILT (INDEX LINKED)",
"AIM",
"VCT",
"OFFSHORE FUND",
"ETP"
};
using (var dealingContext = new dbDealingContainer())
{
return (from fundprice in dealingContext.FundPrices
where (fundprice.FUND_STATUS == "ACTIVE" || fundprice.FUND_STATUS == "SUSPENDED") &&
(fundprice.INVNAME != null || fundprice.INVNAME != "") &&
!fundprice.INVNAME.StartsWith("IFSL Bestinvest") &&
// fundprice.WaterlooTradable == true &&
fundprice.BID_MID_PRICE > 0 && typeList.Contains(fundprice.FUND_TYPE)
&& ((sedols.Length > 0 && sedols.Contains(fundprice.SEDOL_NUMBER))
||sedols.Contains(fundprice.SEDOL_NUMBER_ACC)) || sedols.Length == 0
select new TBI.JV.Business.Objects.Asset
{
AssetName = fundprice.INVNAME,
AssetId = fundprice.Id,
AssetType = fundprice.FUND_TYPE,
Epic = fundprice.INVESTMENT_CODENAME,
StarRating = fundprice.STARLEN,
Sedol = fundprice.SEDOL_NUMBER,
SedolAcc = fundprice.SEDOL_NUMBER_ACC
}).ToList();
}
}
The error is thrown at the following line of code sedols.Length > 0 and also sedols.Length == 0. How do I resolve this. My method should be able to take an empty string array as input and return all records.
Define two variables above the query and than use them instead in the query:
var isGreaterThanZero = sedols.Length > 0;
var isEmpty = sedols.Length == 0;
The Any() extension method is supported by LINQ to Entities.
Using exampleArray.Any() and !exampleArray.Any() means you don't have to declare local variables and fortunately it's a nice, succinct syntax.

LINQ to Entities Method Not Recognized - Extension Method Style

Here's yet another "LINQ to entities does not recognize the method question"... however, isn't the code below doing fundamentally the exact same thing?
Works:
var returnData = from x in MyEntities.MyDBSet
where x.MyDBSetPrimaryKey == id
select new Models.MyModelDTO
{
MyPropOne = (int)x.MyModel.MyOtherPropOne,
MyPropTwo = x.MyOtherPropTwo ?? 0,
MyPropThree = x.MyModel.MyOtherPropThree,
MyPropFour = x.MyModel.MyOtherPropFour,
MyPropFive = x.MyModel.Entity.MyOtherPropFive,
MyPropSix = x.MyModel.MyOtherPropSix == null ? 0 : (decimal)x.MyModel.MyOtherPropSix,
MyPropSeven = x.MyModel.SomeType.MyOtherPropSeven,
MyPropEight = (int)x.MyModel.MyOtherPropEight,
MyPropNine = x.MyModel.MyPropNine == null ? 0 : (int)x.MyModel.MyOtherPropNine,
MyPropTen = x.MyModel.MyOtherPropTen == null ? 0 : (int)x.MyModel.MyOtherPropTen,
MyPropEleven = x.OtherEntity.MyOtherPropEleven,
MyPropTwelve = x.MyOtherpropTwelve
};
Doesn't Work:
The same exact assignments wrapped in an extension method:
public static MyModelDTO ToModelDTO(this MyModel x)
{
return new MyModelDTO()
{
MyPropOne = (int) x.MyModel.MyOtherPropOne,
MyPropTwo = x.MyOtherPropTwo ?? 0,
MyPropThree = x.MyModel.MyOtherPropThree,
MyPropFour = x.MyModel.MyOtherPropFour,
MyPropFive = x.MyModel.Entity.MyOtherPropFive,
MyPropSix = x.MyModel.MyOtherPropSix == null ? 0 : (decimal) x.MyModel.MyOtherPropSix,
MyPropSeven = x.MyModel.SomeType.MyOtherPropSeven,
MyPropEight = (int) x.MyModel.MyOtherPropEight,
MyPropNine = x.MyModel.MyPropNine == null ? 0 : (int) x.MyModel.MyOtherPropNine,
MyPropTen = x.MyModel.MyOtherPropTen == null ? 0 : (int) x.MyModel.MyOtherPropTen,
MyPropEleven = x.OtherEntity.MyOtherPropEleven,
MyPropTwelve = x.MyOtherpropTwelve
};
}
And later called:
var returnData = from x in MyEntities.MyDBSet
where x.MyDBSetPrimaryKey == id
select x.ToModelDto();
Resulting in:
LINQ to Entities does not recognize the method 'MyExtensionMethods.MyModels.MyModelDTO ToModelDTO(API.Models.MyModel)' method, and this method cannot be translated into a store expression.
When the query provider sees that method it doesn't know what to do with it. It can't go in and see the source code of the method, the way it can look into Expression objects and see what is done. It can't evaluate it on the client side as it doesn't have the items yet, and it can't think of any SQL to translate that method call into.
Instead you should write a method that takes an IQueryable and returns another IQueryable, like so:
public static IQueryable<MyModelDTO> ToModelDTO(this IQueryable<MyModel> query)
{
return query.Select(x => new MyModelDTO()
{
MyPropOne = (int)x.MyModel.MyOtherPropOne,
MyPropTwo = x.MyOtherPropTwo ?? 0,
MyPropThree = x.MyModel.MyOtherPropThree,
MyPropFour = x.MyModel.MyOtherPropFour,
MyPropFive = x.MyModel.Entity.MyOtherPropFive,
MyPropSix = x.MyModel.MyOtherPropSix == null ? 0 : (decimal)x.MyModel.MyOtherPropSix,
MyPropSeven = x.MyModel.SomeType.MyOtherPropSeven,
MyPropEight = (int)x.MyModel.MyOtherPropEight,
MyPropNine = x.MyModel.MyPropNine == null ? 0 : (int)x.MyModel.MyOtherPropNine,
MyPropTen = x.MyModel.MyOtherPropTen == null ? 0 : (int)x.MyModel.MyOtherPropTen,
MyPropEleven = x.OtherEntity.MyOtherPropEleven,
MyPropTwelve = x.MyOtherpropTwelve
});
}
Here the mapping is still compiled down into an Expression that the query provider can parse. Now you can do:
var returnData = (from x in MyEntities.MyDBSet
where x.MyDBSetPrimaryKey == id
select x)
.ToModelDTO();
Your problem and possible solutions are not really any different than many of the other "LINQ to entities does not recognize the method" questions.
For examples, see https://stackoverflow.com/a/7259649/120955 and https://stackoverflow.com/a/18901609/120955

Invalid initializer member declarator when projecting into complex types

I was initializing the object in the code below using simple properties but then refactored elsewhere such that DispatchedDocumentDate became DispatchedPhase.DocumentDate. I did this because there is also sold and picked classes using precisely the same properties.
So now in a referencing assembly I have this code which doesn't compile:
public List<ItemMovementEntry> FillItemDispatchMovements(IEntityDateRange imqp)
{
var f = from detail in this.Context.DispatchDetails
join header in this.Context.Dispatches on detail.ClientOrderNumber equals header.ClientOrderNumber
where (detail.ProductCode == imqp.ItemKey)
&& (header.DateOrdered >= imqp.StartDate)
&& (header.DateOrdered <= imqp.EndDate)
orderby header.DateOrdered descending
select new ItemMovementEntry(ItemMovementEntryKind.Dispatch)
{
DispatchedPhase.DocumentDate = ((header.DateOrdered.HasValue) ? header.DateOrdered.Value : new DateTime(1900, 1, 1)),
DispatchedPhase.DocumentLKey = header.ClientOrderNumber,
MaterialItemLkey = detail.ProductCode,
DispatchedPhase.MovementDeltaQty = ((detail.QuantityDelivered.HasValue) ? (-1) * detail.QuantityDelivered.Value : 0),
DispatchedPhase.Comment = string.Empty,
JournalType = "DISPATCHED",
};
return f.ToList<ItemMovementEntry>();
}
I get an :
Invalid initializer member declarator
error message.
Hopefully the intent is clear but I'm not sure how to rewrite. I Googled and got something about Let but it was still unclear.
At this point I will go with adding an extra constructor to the ItemMovementEntry class specifically to deal with this problem.
public ItemMovementEntry(ItemMovementEntryKind comparerMovementKind,
DateTime documentDate,
string documentLKey,
string materialItemKey,
int movementDeltaQty,
string comment)
: this(comparerMovementKind)
{
ItemMovementEntryPhase p = null;
switch (comparerMovementKind)
{
case ItemMovementEntryKind.Sales:
p = this.SoldPhase;
break;
case ItemMovementEntryKind.Picking:
p = this.PickedPhase;
break;
case ItemMovementEntryKind.Dispatch:
p = this.DispatchedPhase;
this.JournalType = "DISPATCHED";
break;
}
p.DocumentDate = documentDate;
p.DocumentLKey = documentLKey;
this.MaterialItemLkey = materialItemKey;
p.MovementDeltaQty = movementDeltaQty;
p.Comment = comment;
}
public List<ItemMovementEntry> FillItemDispatchMovements(IEntityDateRange imqp)
{
var f = from detail in this.Context.DispatchDetails
join header in this.Context.Dispatches on detail.ClientOrderNumber equals header.ClientOrderNumber
where (detail.ProductCode == imqp.ItemKey)
&& (header.DateOrdered >= imqp.StartDate)
&& (header.DateOrdered <= imqp.EndDate)
orderby header.DateOrdered descending
select new ItemMovementEntry(ItemMovementEntryKind.Dispatch,
((header.DateOrdered.HasValue) ? header.DateOrdered.Value : new DateTime(1900, 1, 1)),
header.ClientOrderNumber,
detail.ProductCode,
((detail.QuantityDelivered.HasValue) ? (-1) * detail.QuantityDelivered.Value : 0),
string.Empty){};
return f.ToList<ItemMovementEntry>();
}
Could you build properties in the immediate type that alias set? e.g. where you hold the complex type, make a property that has a setter for the child entity's property that you'd like to set.

LINQ expression works good in LINQPad, but in Silverlight return empty result

This is a simple left outer join in LINQ (like the MS example).
It works good in LINQPad:
from x in Nevtars
join c in Tetsziks on x.NevtarID equals c.NevtarID into ctemp
from subc in ctemp.DefaultIfEmpty()
select new { x.Nev, subc.Tetszes }
The result:
-----------------
Nev Tetszes
Őszike 1
Őzike null
Pintyőke null
Regő null
Rezső null
Szellő null
Szellőke 2
This expresion in Silverlight DomainSource side:
public IQueryable<MyP> GetTetszik()
{
var q2 = from x in this.Context.Nevtars
join c in this.Context.Tetszik on x.NevtarID equals c.NevtarID into ctemp
from subc in ctemp.DefaultIfEmpty()
select new MyP
{
Nev = x.Nev,
Tetszes = (subc == null ? 0 : (Int32)subc.Tetszes)
};
return q2;
}
public class MyP
{
[Key]
public string Nev { get; set; }
public int Tetszes { get; set; }
}
And in the "Entity side":
DomainService1 ctx2 = new DomainService1();
xxxGrid.ItemsSource = ctx2.MyPs;
var q2 = ctx2.GetTetszikQuery();
ctx2.Load(q2);
The result will be an empty grid... :(
Please help me!
Thanks!
Does the domain service provide a way for the ItemsSource to catch the changes? If not, reassign it to the ItemsSource after you grabbed the data from the database.

Categories