HotChocolate 从数据库转换数据?

Zul*_*kas 5 c# entity-framework graphql hotchocolate

我正在尝试使用 Hot Chocolate GraphQL 库来转换数据的形状,然后再将其发送回客户端。

举例来说,我有一个想要返回的对象:

public class SimplePersonData
{
    public string First { get; set; }
    public string Last { get; set; }
    public string HomeTown { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的数据库实体如下所示:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public int HomeAddressId { get; set; }
    public virtual Address HomeAddress { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果没有 GraphQL,我会使用实体框架来执行此操作(假设我的两个类有一个典型的 EF dbcontext)

public async Task<SimplePersonData> GetPersonData(int id)
{
    var person = await dbContext.People
        .Include(p => p.HomeAddress)
        .FirstOrDefaultAsync(p => p.Id == id);

    return new SimplePersonData
    {
        First = person.FirstName,
        Last = person.LastName,
        HomeTown = person.Address?.City
    };
}
Run Code Online (Sandbox Code Playgroud)

使用 HotChocolate,我定义了一个查询类,该类具有一个类似于用于获取人员对象的解析器。使用 [UseProjection] 属性,它将执行一些背景魔法,知道如何在不过度获取的情况下获取数据:

public class Query
{
    [UseProjection]
    public async Task<Person> GetPerson([Service] DbContext dbContext, int id)
    {
        return await dbContext.People.FirstOrDefault(p => p.Id == id);
    }
}
Run Code Online (Sandbox Code Playgroud)

但如果我想将对象转换为我的SimplePersonData对象,事情就会开始变得混乱。我没有看到任何简单的方法可以在继续使用投影的同时轻松转换数据。这可以在 HotChocolate 中实现吗?如果可以,如何实现?据我了解,问题在于,由于返回的对象具有不同的字段名称,因此投影引擎无法准确知道要获取的内容。我考虑过使用 AutoMapper 来实现此目的,但它似乎更改了从数据库中获取映射所需的所有内容的查询。

[UseProjection]
public async Task<SimplePersonData> GetSimplePersonData([Service] DbContext dbContext, int id)
{
    // Using AutoMapper provides promising results here, but causes the data to overfetch.
    // If the GraphQL request doesn't include 'homeTown' that data will still be fetched and then discarded.
    return await dbContext.People.ProjectTo<SimplePersonData>(_mapper.MapperConfiguration).FirstOrDefaultAsync(p => p.Id == id);
}

// sample mapping profile:
public class SimplePersonDataMappingProfile : Profile
{
    public SimplePersonDataMappingProfile()
    {
        CreateMapping<Person, SimplePersonData>()
            .ForMember(dst => dst.First, exp => exp.MapFrom(src => src.FirstName))
            .ForMember(dst => dst.Last, exp => exp.MapFrom(src => src.LastName))
            .ForPath(dst => dst.HomeTown, exp => exp.MapFrom(src => src.Address.City));
    }
}
Run Code Online (Sandbox Code Playgroud)

TLDR:我们的域模式与我们的数据库模式没有直接关系。有没有办法利用投影功能来准确获取我们需要的数据,将数据库数据转换为领域数据?