Home > Software engineering >  A lambda expression with a expression body cannot be converted to an expression tree C# entity frame
A lambda expression with a expression body cannot be converted to an expression tree C# entity frame

Time:06-04

I have an entity table with below model

   public class VulnerabilityImportFileLog
    {
        public Collection<Vulnerability> Vulnerability { get; set; }
    }

Trying to return an string value using the select statement in the entity framework query

var vulnerabilityImportFileLogSelect = vulnerabilityImportFileLogQuery
        .Select(vulnerabilityImportFileLog =>
            new VulnerabilityImportedScansListViewDto
            {
                AssetName = vulnerabilityImportFileLog.Vulnerability.Select(y =>
                    {
                        if (y.AssetHostIPOrDomain.HostIPAssetId.HasValue)
                            return y.AssetHostIPOrDomain.HostIPAsset.Title;
                        else if (y.AssetHostIPOrDomain.DomainAssetId.HasValue)
                            return y.AssetHostIPOrDomain.DomainAsset.Title;
                        else
                            return y.AssetHostIPOrDomain.HostIPOrDomain;
                    }
                ).Distinct().ToList()
            });

Where AssetName is of type List<string> and getting an exception as A lamda expression with a statement body cannot be converted to an expression tree

enter image description here

An suggested answer was to use AsEnumerable(), but even that not solved the issue.

CodePudding user response:

You can solve the problem by using linq query syntax with 'let' keyword:

AssetName = (from y in vulnerabilityImportFileLog.Vulnerability
    let resultString = y.AssetHostIPOrDomain.HostIPAssetId.HasValue
      ? y.AssetHostIPOrDomain.HostIPAsset.Title
      : y.AssetHostIPOrDomain.DomainAssetId.HasValue
      ? y.AssetHostIPOrDomain.DomainAsset.Title
      : y.AssetHostIPOrDomain.HostIPOrDomain
  select resultString
)
.ToList()
.Distinct();
    

CodePudding user response:

Assuming vulnerabilityImportFileLogQuery is an IQueryable<vulnerabilityImportFileLog> then a typical way to fetch details from the associated Vulnerability relations would be via a SelectMany. Given you need to do substitution depending on what is available, one option would be to do a double-projection. The first pass selects and materializes just the details we want to inspect, then the second pass composes the results.

vulnerabilityImportFileLogQuery.SelectMany(x => new 
{
    x.Vulnerability.AssetHostIpOrDomain.HostIpOrDomain,
    HostIpAssetTitle = x.Vulnerability.AssetHostIpOrDomain.HostIpAsset.Title,
    DomainAssetTitle = x.Vulnerability.AssetHostIpOrDomain.DomainAsset.Title
}).ToList()
.Select(x => x.HostIpAssetTitle ?? DomainAssetTitle ?? HostIpOrDomain)
.Distinct()
.ToList();

What this essentially does is fetch the 3 values, our default HostIpOrDomain value, and the Titles from the HostIpAsset and DomainAsset if they are available. EF will return #null if the entities aren't associated or the Title is #null. This query is materialized using the ToList, then from that we Select the title to use based on a null check, before taking our Distinct set.

Hopefully that gives you a few ideas as a starting point.

  • Related