14

我正在使用 API 服务器(ASP.NET Core)。为了防止将来出现意大利面条式代码和其他讨厌的东西,我按照 Clean Architecture/CQRS(使用 MediatR)设计了系统。

我正在考虑将 GraphQL 用于 API 而不是 REST(热巧克力 GraphQL)。在 HotChocolate GraphQL 的几个示例中,使用 GraphQL-EF 机制直接查询数据库。虽然这看起来很有好处,但我担心从长远来看这可能会使代码复杂化。数据库结构可能会发生变化等。在我看来,API 应该与存储库层保持分离。即使做更多的工作,我相信 GraphQL 应该改为与 CQRS 通信。

请你的想法!

4

4 回答 4

4

尽管不是一个封闭式回答“是或否”的问题,但我同意你的看法。我怀疑这些例子中的大多数可能只是为了演示。如果不分离合约、业务逻辑和数据层,似乎很难确保 SOLID 原则。

像您一样使用 CQRS 和 MediatR,您可以更轻松地执行 DDD。因此,命令/查询位于Application层似乎很自然,而存储库的实现可以转到Infrastructure。另一方面,API 合约将进入表示层。

事实上,我们可以根据我们的业务需求,在应用层中自始至终开发几个功能。这些功能可能会提供不同的演示模块,或者以不同方式公开的 API、UI 应用程序等。另一方面,这些功能可以依赖于各种基础设施数据存储库或外部源,例如。

Microsoft 在这里对常见的 Web 架构进行了很好的分析,这里重点关注 Clean Architecture 。

最后,在我看来,是的,您可以在Presentation中设置 GraphQL API,在Application层中使用 CQRS 设计并使用 MediatR 编排的业务逻辑,以及在Infrastructure中实现的数据存储库(尊重在应用)。

于 2021-02-21T11:45:43.093 回答
1

这只是 GraphQL 的冰山一角,使用它还有更多我将要向您展示的内容。只是想把它作为免责声明。

使用 GraphQL 时,您有一个继承自 ObjectGraphType 的 Query 对象和一个继承自的 Schema 对象,以实现您的自定义查询、订阅和突变。

这些示例用于处理管理员问题的服务,这就是为什么您会经常看到“管理员”一词的原因。

这个实现的核心是一个继承自 ObjectGraphType 的对象:

    public class AdminQuery : ObjectGraphType
    {
        public AdminQuery(IServiceProvider sp)
        {
            ///Used to retrieve a list of users
            Field<ListGraphType<UserType>>()
                .Name("users")
                .Description(nameof(User))
                .ResolveAsync(
                async context
                => await sp.GetAsync<User>()); ////This is the extension method defined below
        }
    }

    ///GraphQL object that represents the User object
    ///Since there were numerous data models I created an abstract class
    ///to offload some of the boiler plate code
    public class UserType : IdentityDataTypeBase<User>
    {
        public UserType(IServiceProvider sp) : base()
        {
            ///This allows access to the properties of the User class
            ///The second parameter determines whether to allow null
            Field(c => c.Name, true);
            Field(c => c.Email, true);
            Field(c => c.FirstName, true);
            Field(c => c.LastName, true);
            Field(c => c.UserName, true);
        }
    }

    ///Abstract class that handles Identity Models being queried    
    public abstract class IdentityDataTypeBase<T> : ObjectGraphType<T> where T : IdentityBase
    {
        public IdentityDataTypeBase()
        {
            Field(c => c.Id, false)
                .Name(///Name of your property)
                .Description(///Description of the property);            
        }
    }

    ///Extension method defined to simplify data access
    public static Task<IEnumerable<T>> GetAsync<T>(this IServiceProvider sp)
    {           
        ///if you use IRepository<T>
        var repo = sp.GetRequiredService<IRepository<T>>();
        
        ///if you want to directly us the DbContext
        var repo = sp.GetRequiredService<DbContext>();

        ///Use the instance of whichever to retrive the object from the database
    }

此示例希望表明您只需要访问您正在查询的数据模型以及您将用于访问该数据的数据存储。

于 2021-03-01T14:41:06.300 回答
1

您是否考虑过将 GraphQL 用于 CQRS 中的 Q 以及其他一些 RPC 机制用于 CQRS 的命令端?

Mark Grenfell 在他关于 gRPC 的伦敦 2020 NDC 演讲中强调了在没有 api 版本控制的情况下支持可演进的灵活性的重要性,这一点似乎证实了您对数据库模式和 GraphQL 之间紧密耦合的担忧。

NDC 讲座:从 WCF 到 gRPC - Mark Rendle | 国家数据中心会议

以下博客文章演示了如何使用动态类型创建成形的实体框架查询。我还没有探索如何将这种技术连接到 GraphQL,但这可能会提供足够的模式抽象。

带有实体框架核心的 CQRS

于 2020-08-04T11:28:44.857 回答
0

当您考虑 GraphQL 时,请查看 GraphQL 需要访问的不同内容。我需要访问表示数据的模型,并且它需要访问数据源,无论是 DbContext 类还是 IRepository。您从实际实现中抽象得越多,您就越能将自己与重大更改隔离开来。我在上一个项目中实现了 GraphQL,并为所有与 GraphQL 相关的类创建了一个单独的库。GraphQL 库只需要访问带有数据模型的库,它也有接口。然后应用层只需要引用 GraphQL 库,以便它可以调用将其插入 DI 管道的扩展方法。

于 2021-02-26T15:33:45.873 回答