LINQ to Entities Method Not Recognized - Extension Method Style - c#

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

Related

Why is there Unreachable code detected in C# - Nested ternary operation into if-else statement

before that, Im a beginner in c#. I had change nested ternary operations into independent statement but when I change it to if-else statement, it says that it is unreachable code
here are the lines that I had problem with
FlowLineSize = sumOfAllWells,
NoOfWell = _brainConceptDCDetailsInput.HydrocacbornType == "Gas"
? _brainConceptDCDetailsInput.GasFlowlineSize
: _brainConceptDCDetailsInput.HydrocacbornType == "Oil"
? _brainConceptDCDetailsInput.OilFlowlineSize
: 0
what is the syntax format to put if else statement after the sumOfAllWells,, I already tried putting if statement after it and it say unreachable code
Edited:
here is the full code,
public BrainSubseaJumperInputDTO FillInputDTO(ProjectInfoDTO projectInfoInput = null, BrainConceptsInputDTO conceptInput = null)
{
var sumOfAllWells = conceptInput?.ConceptDCDetailsInputDTO
.Sum(x => x.OilProducerWell + x.GasProducerWell + x.WaterInjectorWell + x.GasInjectorWell) ?? 0;
return new BrainSubseaJumperInputDTO()
{
FlowLineSize = sumOfAllWells,
NoOfWell = _brainConceptDCDetailsInput.HydrocacbornType == "Gas"
? _brainConceptDCDetailsInput.GasFlowlineSize
: _brainConceptDCDetailsInput.HydrocacbornType == "Oil"
? _brainConceptDCDetailsInput.OilFlowlineSize
: 0
};
}
If this was valid code: After the edit, it makes more sense ...
FlowLineSize = sumOfAllWells, // <== Typo here? No, it's part of something bigger
NoOfWell = _brainConceptDCDetailsInput.HydrocacbornType == "Gas" ?
_brainConceptDCDetailsInput.GasFlowlineSize :
_brainConceptDCDetailsInput.HydrocacbornType == "Oil" ?
_brainConceptDCDetailsInput.OilFlowlineSize
:0
then that ternary abomination would roughly translate to
if( _brainConceptDCDetailsInput.HydrocacbornType == "Gas")
{
NoOfWell = _brainConceptDCDetailsInput.GasFlowlineSize;
}
else
{
if(_brainConceptDCDetailsInput.HydrocacbornType == "Oil")
{
NoOfWell = _brainConceptDCDetailsInput.OilFlowlineSize;
}
else
{
NoOfWell = 0;
}
}
assuming there is a NoOfWell declared.
But as pointed out in comments: There are better (i.e. cleaner, more readable) ways to express this.
For example switch expressions:
NoOfWell = _brainConceptDCDetailsInput.HydrocarbonType switch
{
"Gas" => _brainConceptDCDetailsInput.GasFlowlineSize,
"Oil" => _brainConceptDCDetailsInput.OilFlowlineSize,
_ => 0
}
If you can make HydroCarbonType a class then this maybe could be a property of that.
If you could make it an Enum, you could use Dictionary and ExtentionMethods ...
After seeing the full code, you could also make the logic part of a DTO Builder / Factory ...
static BrainSubseaJumperInputDTO FromBrainConceptDetailsInput(
int sum,
WhateverTypeThatIs input )
{
return new BrainSubseaJumperInputDTO(){
FlowLineSize = sum,
NoOfWell = input.HydrocarbonType switch
{
"Gas" => input.GasFlowlineSize,
"Oil" => input.OilFlowlineSize,
_ => 0
}
};
}
That would boil down your code to
public BrainSubseaJumperInputDTO FillInputDTO(ProjectInfoDTO projectInfoInput = null, BrainConceptsInputDTO conceptInput = null)
{
var sumOfAllWells = conceptInput?.ConceptDCDetailsInputDTO
.Sum(x => x.OilProducerWell +
x.GasProducerWell +
x.WaterInjectorWell +
x.GasInjectorWell)
?? 0;
return FromBrainConceptDetailsInput( sumOfAllWells,
_brainConceptDCDetailsInput);
}

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.

Expression predicate must be built separately with if and else blocks?

I have 2 versions of codes for class method "GetUserRoles". Version 1 always works OK while Version 2 is not working if passed-in argument "exludeRoleNames" for that method is absent and exception "Null object reference" is thrown as a result. I would like to understand why Version 2 codes are not always working, and why Version 1 codes require building predicate with "if" and "else" blocks. Thank you in advance.
Version 1:
The following codes are always working. You could notice that there are separate "if" and "else" blocks to build local variable Expression<Func<UserRoleInApplication, bool>> predicate
public List<UserInRoleViewModel> GetUserRoles(long userId, params string[] exludeRoleNames)
{
List<UserInRoleViewModel> results = null;
IQueryable<UserInRoleViewModel> items = null;
Expression<Func<UserRoleInApplication, bool>> predicate = null;
if (exludeRoleNames.Count() <= 0)
{
predicate = x => true;
}
else
{
predicate = x => !exludeRoleNames.Contains(x.UserRole.RoleName);
}
items = from uir in _repository.GetQuery<UserInRole>(x => x.UserId == userId)
join ura in _repository.GetQuery<UserRoleInApplication>(predicate)
on uir.UserRoleInApplicationId equals ura.UserRoleInApplicationId
into g
from item in g
select new UserInRoleViewModel
{
UserInRoleId = uir.UserInRoleId,
UserId = uir.UserId,
UserRoleInApplicationId = uir.UserRoleInApplicationId
};
if (items != null && items.Any())
{
results = new List<UserInRoleViewModel>();
results = items.ToList();
}
return results;
}
Version 2:
However, the following codes throw exception "Null object reference" when calling method GetUserRoles such as GetUserRoles(long userId) without passed-in argument "exludeRoleNames". You could notice that there are no separate "if" and "else" blocks for the codes to form local variable Expression<Func<UserRoleInApplication, bool>> predicate:
public List<UserInRoleViewModel> GetUserRoles(long userId, params string[] exludeRoleNames)
{
List<UserInRoleViewModel> results = null;
IQueryable<UserInRoleViewModel> items = null;
// Note: one line code and no separate "if" and "else" blocks *************
Expression<Func<UserRoleInApplication, bool>> predicate = x => exludeRoleNames.Count() <= 0 ? true : !exludeRoleNames.Contains(x.UserRole.RoleName);
items = from uir in _repository.GetQuery<UserInRole>(x => x.UserId == userId)
join ura in _repository.GetQuery<UserRoleInApplication>(predicate)
on uir.UserRoleInApplicationId equals ura.UserRoleInApplicationId
into g
from item in g
select new UserInRoleViewModel
{
UserInRoleId = uir.UserInRoleId,
UserId = uir.UserId,
UserRoleInApplicationId = uir.UserRoleInApplicationId
};
if (items != null && items.Any()) // Note: throw exception "Null object reference" if parameter "exludeRoleNames" is absent on calling method GetUserRoles such as GetUserRoles(long userId);
{
results = new List<UserInRoleViewModel>();
results = items.ToList();
}
return results;
}
Try changing this:
Expression<Func<UserRoleInApplication, bool>> predicate = x => exludeRoleNames.Count() <= 0 ? true : !exludeRoleNames.Contains(x.UserRole.RoleName);
To this:
Expression<Func<UserRoleInApplication, bool>> predicate = x => true;
if(exludeRoleNames != null)
{
foreach(string exl in exludeRoleNames)
{
string temp = exl;
predicate = predicate.Or(x=>x.UserRole.RoleName == temp);
}
}
The problem is that you're trying to call Count() on exludeRoleNames - which is null. So, rather than check Count(), compare it to null. If it is null, then you can treat it as an empty array. If it isn't null, then check it's contents.
The other problem is that you can't use string[].Contains in a query context. Entity Framework (which I assume you are using) doesn't support that. So, you have to build out the predicate.
I re-write the following codes and they are working. In case of absent parameter "exludeRoleNames", the codes creat an empty string array:
public List<UserInRoleViewModel> GetUserRoles(long userId, params string[] exludeRoleNames)
{
List<UserInRoleViewModel> results = null;
IQueryable<UserInRoleViewModel> items = null;
exludeRoleNames = !exludeRoleNames.Any() ? new string[] { } : exludeRoleNames; // a MUST
Expression<Func<UserRoleInApplication, bool>> predicate = x => !exludeRoleNames.Contains(x.UserRole.RoleName);
items = from uir in _repository.GetQuery<UserInRole>(x => x.UserId == userId)
join ura in _repository.GetQuery<UserRoleInApplication>(predicate)
on uir.UserRoleInApplicationId equals ura.UserRoleInApplicationId
into g
from item in g
select new UserInRoleViewModel
{
UserInRoleId = uir.UserInRoleId,
UserId = uir.UserId,
UserRoleInApplicationId = uir.UserRoleInApplicationId
};
if (items != null && items.Any())
{
results = new List<UserInRoleViewModel>();
results = items.ToList();
}
return results;
}

Singleordefault call only returning null when within a ternary operator

I've found a fairly odd occurrence. When the following code is executed, mapFound evaluates to null despite 'mapLst' being populated and 'foo' also finding a matching map within the collection. Can anyone think of a reason for why that might be?
var mp = new MapObj() {
keyObj = new KeyObj() { name = "Bob" },
valObj = new ValObj() { type = "Type1" },
category = "cat"
}
var foo = mapLst.SingleOrDefault(map => map.keyObj.name.Equals("Bob") &&
map.valObj.type.Equals("Type1") &&
map.category.Equals("cat"));
var mapFound = mapLst != null ? mapLst.SingleOrDefault(map =>
map.keyObj.name.Equals("Bob") &&
map.valObj.type.Equals("Type1") &&
map.category.Equals("cat"))
: null;

Get index in a IQueryable result

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;

Categories