Convert Entity with navigation property to DTO usi

2019-09-12 02:10发布

问题:

Suppose I have following entities and dtos

public class Country
{
    public List<NameLocalized> NamesLocalized;
    public CountryData Data;
}

public class NameLocalized
{
    public string Locale;
    public string Value;
}

public class CountryData
{
    public int Population;
}

public class CountryDto
{
    public String Name;
    public CountryDataDto Data;
}

public class CountryDataDto
{
    public int Population;
}

I need to convert Country to CountryDto (and ideally, I want to make a single query to the database). I have received few suggestions in my other questions on Stackoverflow, and can now accomplish the task, but only partially. I am stuck at how to convert navigation property (CountryData in this case). I was suggested to use LINQKit for this, but have no idea how to implement it. Here is my code which populates only Name property but not Data navigation property.

public static async Task<List<CountryDto>> ToDtosAsync(this IQueryable<Country> source, string locale)
{
    if(source == null)
    {
        return null;
    }

    var result = await source
        .Select(src => new CountryDto
        {    
           Name = src.NamesLocalized.FirstOrDefault(n => n.Locale == locale).Name
        })
        .ToListAsync();

    return result; 
}

回答1:

This answer gave me the hint for my solution. You need to use LINQKit and build Expression to convert the navigation property.

public static Expression<Func<CountryData, CountryDataDto>> ConverterExpression = cd => new CountryDataDto
        {
            Population = cd.Population
        };

public static async Task<List<CountryDto>> ToDtosAsync(this IQueryable<Country> source, string locale)
{
    if(source == null)
    {
        return null;
    }

    var result = await source
        .AsExpandable
        .Select(src => new CountryDto
        {    
           Name = src.NamesLocalized.FirstOrDefault(n => n.Locale == locale).Name
           Data = ConverterExpression.Invoke(src.Data)
        })
        .ToListAsync();

    return result; 
}