在 Hot Chocolate 框架中使用 DTO(使用 EFCore)

发布于 2025-01-17 15:41:32 字数 1417 浏览 0 评论 0原文

我们在热巧克力框架内使用EF核心来访问一些SQL数据库。 为了克服计算字段的问题(描述在这里)我们使用DTOS。

在下面的示例中,这很好。在查询“ foo”时,称为“ getfoo”方法,它使用计算参数创建了一个“ foodto”对象。

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<fooDTO> GetFoo([Service] ApiDbContext context) {
    return context.fooSet.AsEnumerable().Select(f => CreateFooDTO(f)).AsQueryable();
}

private static fooDTO CreateFooDTO(foo f){
    return new fooDTO{
        param1 = f.param1,
        param2 = f.param2,
        computedParam3 = param2 - param1,
        };
}

但是,当我们想在查询“ bar”引用“ foo”时使用dtos时,事情出了问题:

{
   bar {
      foo
   }
}

对于那种情况,我们提供了以下方法:

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<barDTO> GetBar([Service] ApiDbContext context){
    return context.barSet.AsEnumerable().Select(b => CreateBarDTO(b)).AsQueryable();
}

private static barDTO CreateBarDTO(bar b){
    return new barDTO{
        param1 = b.param1,
        param2 = b.param2,
        param3 = CreateFooDTO(b.foo)
    };
}

这里的“ b.foo”似乎总是无效的,这意味着从未实现食物。

我的问题:

  • 这个问题与热巧克力或EF核心有关吗?
  • 在这种情况下,如何正确使用DTO?

We are using EF Core within the Hot Chocolate framework to access some SQL databases.
To overcome the issue with computed fields (described here) we make use of DTOs.

This works perfectly fine in the example below. When querying for "Foo", the "GetFoo" method is called which created a "fooDTO" object with the computed parameter.

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<fooDTO> GetFoo([Service] ApiDbContext context) {
    return context.fooSet.AsEnumerable().Select(f => CreateFooDTO(f)).AsQueryable();
}

private static fooDTO CreateFooDTO(foo f){
    return new fooDTO{
        param1 = f.param1,
        param2 = f.param2,
        computedParam3 = param2 - param1,
        };
}

However, things go wrong when we want use DTOs when querying for "Bar" referring "Foo":

{
   bar {
      foo
   }
}

For that case we provided the following methods:

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<barDTO> GetBar([Service] ApiDbContext context){
    return context.barSet.AsEnumerable().Select(b => CreateBarDTO(b)).AsQueryable();
}

private static barDTO CreateBarDTO(bar b){
    return new barDTO{
        param1 = b.param1,
        param2 = b.param2,
        param3 = CreateFooDTO(b.foo)
    };
}

Here "b.foo" seems to be always null, meaning that fooDTO is never materialized.

My questions:

  • Is this problem related to Hot Chocolate or EF Core?
  • How to properly use DTOs in this case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫腻 2025-01-24 15:41:32

您在这里有几种选择,使用AutoMapper,它是projectto 或在这种情况下有助于使用库。

我建议使用 linqkit 。它需要仅配置dbContextoptions

builder
    .UseSqlServer(connectionString)
    .WithExpressionExpanding(); // enabling LINQKit extension

由于EF Core只能与ExpressionTree一起使用,因此您必须以某种方式将此树传递到Linq查询。 linqkit具有标记方法及其表达模拟的能力。然后,在扩展过程中,它将在查询翻译过程中注入所需的零件。

假设您已经配置了dbContext以使用linqkit,则可以通过ExpandBableAbeatTribute

[Expandable(nameof(CreateBarDTOmpl))]
public static barDTO CreateBarDTO(bar b)
{
    throw new NotImplementedExpeption()
}

private static Expression<Func<bar, barDTO>> CreateBarDTOmpl()
{
    return b => new barDTO
    {
        param1 = b.param1,
        param2 = b.param2,
        param3 = CreateFooDTO(b.foo)
    };
}

[Expandable(nameof(CreateFooDTOImpl))]
public static fooDTO CreateFooDTO(foo f)
{
   throw new NotImplementedExpeption()
}

private static Expression<Func<foo, fooDTO>>fooDTO CreateFooDTOImpl()
{
    return f => new fooDTO
    {
        param1 = f.param1,
        param2 = f.param2,
        computedParam3 = f.param2 - f.param1,
    };
} 

用法很简单:

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<fooDTO> GetFoo([Service] ApiDbContext context) 
{
    return context.fooSet.Select(f => CreateFooDTO(f));
}

它将与AutoMapper的<:代码> projectto 但不配置映射。稍后,您可能会发现简化许多类似的谓词或其他重复的LINQ查询部分是有用的。

You have several choices here, using Automapper and it's ProjectTo or using libraries which helps in such case.

I would suggest to use LINQKit. It needs just configuring DbContextOptions:

builder
    .UseSqlServer(connectionString)
    .WithExpressionExpanding(); // enabling LINQKit extension

Since EF Core can work only with ExpressionTree, you have to pass this tree to LINQ query somehow. LINQKit has ability to mark methods and their Expression analogue together. Then during expanding it will inject needed parts during query translation.

Assuming that you have configured your DbContext to use LINQKit, you can extend your methods with ExpressionTree versions via ExpandableAttribute:

[Expandable(nameof(CreateBarDTOmpl))]
public static barDTO CreateBarDTO(bar b)
{
    throw new NotImplementedExpeption()
}

private static Expression<Func<bar, barDTO>> CreateBarDTOmpl()
{
    return b => new barDTO
    {
        param1 = b.param1,
        param2 = b.param2,
        param3 = CreateFooDTO(b.foo)
    };
}

[Expandable(nameof(CreateFooDTOImpl))]
public static fooDTO CreateFooDTO(foo f)
{
   throw new NotImplementedExpeption()
}

private static Expression<Func<foo, fooDTO>>fooDTO CreateFooDTOImpl()
{
    return f => new fooDTO
    {
        param1 = f.param1,
        param2 = f.param2,
        computedParam3 = f.param2 - f.param1,
    };
} 

Then usage is simple:

[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<fooDTO> GetFoo([Service] ApiDbContext context) 
{
    return context.fooSet.Select(f => CreateFooDTO(f));
}

It will generate the same projection as Automapper's ProjectTo but without configuring mapping. Later you may find how it useful to simplify a lot of similar predicates or other repetitive LINQ query parts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文