Search code examples
c#sql.netlinq

Replace specific Objects in IQueryable query in .NET fails


I have two queries (IQueryable<ApplicationSettingsDto>) written in query syntax in my .NET Web API. They both return DTO Models.

First query returns all Objects with an empty Text
Field(ApplicationSettingsto.Text). Second query return specific Objects which contain some information in Text Field(ApplicationSettingsto.Text).

My goal is to replace only specific entities from first query which have the same KeyName (query1.DTO.KeyName == query2.DTO.KeyName), so that my output contains some objects with empty TextField and some objects with information in TextField.

Can I use to the query syntax for this or do I need to change to method syntax?

Below my DTO Model and the queries:

DTO Model

public class ApplicationSettingsDto
{
    public string KeyName { get; set; }

    // User View
    public string Name { get; set; }

    public int Typ { get; set; }

    // '*' if Node else some value
    public string Wert { get; set; }

    public string Text { get; set; }

    public string DefaultValues { get; set; }

    public bool IsNode { get; set; }

}

Querys(IQueryable):

// For simplicity I left out the detailed query
var query1; // returns all DTOs with empty Text Field
var query2; // returns only DTOs which contain Informations in Text Field

// This is the query part I don't understand how to implement
var result; // Should replace the specific objects from query1 with objects from query2 if (query2.Object.KeyName.Equals(query1.Object.KeyName)) 

Solution

  • Although you didn't mention it, let's assume your queries contain the same type of elements. So it is not that the first sequence contains strings and the second sequence contains DateTimes.

    IQueryable<TSource> query1 = ...
    IQueryable<TSource> query2 = ...
    

    Therefore, if you only replace some elements from query1 with elements from query2, then the result is of course also an IQueryable<TSource>.

    You didn't specify what you want if there are several objects in query2 with the same KeyName, worse: if there are also several objects in query1 with the same KeyName.

    And what if one of the elements in your query has a null Object? In that case you can't ask for Object.KeyName.

    Let's assume all elements have a non-null Object, and all KeyNames are unique.

    The solution is a GroupJoin on common Object.KeyName, if an item in query1 has one or more query2 items with the same Object.KeyName, take one of the query2 items (let's take the first, shall we?), if there are no matching q2, take the q1

    var result = query1
        .GroupJoin(query2,             // GroupJoin query1 and query2
            q1 => q1.Object.KeyName,   // from every query1 element take Object.KeyName
            q2 => q2.Object.KeyName,   // from every query2 element take Object.KeyName
            (q1, matchingQ2s) =>       // from every q1 with all its matching q2 objects
                                       // take the first matching q2, or q1 if there is none
                matchingQ2s.FirstOrDefault() ?? q1
    
      );
    

    Simple comme bonjour!