简体   繁体   中英

EF Core 5.0 Union Linq Query with sub selects not working

Goal:

I want to combine information from two tables (entityA & entityB) with different Properties to one unionDto. I am trying to implement this with a union operation to filter different entities in the Database at the same time.

But the structure I am using requires Versions which need to be filtered before the union query.

Some Additional Information:

So what I am trying to do in the last query is: First I project information from table "entityA" and "entityB" to a universal "anonymous" type (with union). Then I am trying to apply pagination and then I am trying to "project" the new anonymous result to a UnionDto . So this would result in one UnionDto which has "information from 2 different tables" .

I have created an example of my problem with two entities which have Versions:

Entities:

class entityA {
    public List<VersionA> Versions;
    public Guid CreatedBy;
}

class entityB {
    public List<VersionB> Versions;
    public Guid CreatedBy;
}

class VersionA {
    public string TitleA;
    public Instant EffectiveTo;
}

class VersionB {
    public string TitleB;
    public Instant EffectiveTo;
}

class UnionDto{
    public string Title;
    public Guid Creator;
}

I am setting up the query like this:

var queryA = databaseContext.Set<entityA>()
                .Select(entity => new
                {
                    Versions = entity.Versions
                        .Where(version => version.EffectiveTo > now)    /* Filtering newest entity Version */ 
                        .Select(versionDetail => new               /* Selecting only the Title of this Version */
                        {
                            Title = versionDetail.TitleA
                        })
                        .ToList(),
                    Creator = entity.CreatedBy,
                });

var queryB = databaseContext.Set<entityB>()
                .Select(entity => new
                {
                    Versions = entity.Versions
                        .Where(version => version.EffectiveTo > now)
                        .Select(versionDetail => new 
                        {
                            Title = versionDetail.TitleB
                        })
                        .ToList(),
                    Creator = entity.CreatedBy,
                });

Executing the query:

var unionDto = await queryA
                .Union(queryB)
                .Skip(0)
                .Take(20)
                .Select(x => new UnionDto
                {
                    Title= x.Versions.FirstOrDefault() == null ? null : 
                        x.Versions.FirstOrDefault().Title,
                    Creator= x.Creator,
                })
                .ToListAsync();

It seems like that i am not able to use sub selects inside a union query and I am getting the following error:

Set operations: support when placed after client evaluation in projection #16243

I dont know, what I have to do to get around this issue, since I dont really want to go throught all of my entities seperatly with seperate Database queries.

Currently using Ef core Version: 5.0.100-preview

Now this is just an example. This would be required for at least 10 entities, which would result in high Database traffic if done for each entity seperatly.

Any ideas?

If you need only title of first version from each recordset, your query can be simplified and EF Core can translate this query.

 var queryA = 
    from entity in databaseContext.Set<entityA>()
    from version in entity.Versions
    where version.EffectiveTo > now
    select new 
    { 
       Title = version.Title, 
       Creator = entity.CreatedBy 
    }

 var queryB = 
    from entity in databaseContext.Set<entityB>()
    from version in entity.Versions
    where version.EffectiveTo > now
    select new 
    { 
       Title = version.Title, 
       Creator = entity.CreatedBy 
    }

 var versions = queryA.Union(queryB);

 var unionDto = await versions
            .Skip(0)
            .Take(20)
            .Select(x => new UnionDto
            {
                Title = x.Title,
                Creator = x.Creator,
            })
            .ToListAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM