在 Relay 中创建嵌套突变会引发未知字段

Posted

技术标签:

【中文标题】在 Relay 中创建嵌套突变会引发未知字段【英文标题】:Creating nested mutation in Relay throws unknown field 【发布时间】:2020-01-06 09:45:59 【问题描述】:

我这里有我的帐户表和我的设置表。基本上,一个帐户有很多设置,我计划能够使用中继使用 GraphQL 输入这些设置。不幸的是,它在纱线期间抛出了以下错误

relay:
ERROR:
GraphQLParser: Unknown field `maxAllowedRecords` on type `AccountObject`. Source: document `CreateAccountMutation` file: `mutations/CreateAccountMutation.js`.

maxAllowedRecords 不是 Account 对象中的字段,而是设置表中与特定帐户对象相关的设置。我有下面的 SQLAlchemy:

class Account(Base):
    __tablename__ = 'accounts'

    id = Column(Integer, primary_key=True)
    raw_id = Column('id', Integer, primary_key=True)
    name = Column(String(255), nullable=False)
    num_licenses = Column(Integer, nullable=False)
    import_records_limit = Column(Integer, nullable=False)
    max_failed_logins = Column(Integer, nullable=False)
    status = Column(Integer, nullable=False)
    employee_lists = relationship('EmployeeList')
    users = relationship('User')
    policies = relationship("Policy", secondary=accounts_policies, back_populates="accounts")
    settings = relationship('AccountSetting')

class AccountSetting(Base):
    __tablename__ = 'account_settings'

    id = Column(Integer, primary_key=True)
    account = relationship('Account')
    account_id = Column(Integer, ForeignKey('accounts.id'))
    name = Column(String(30))
    value = Column(String(1000))

这里是账户变异方法

class CreateAccountMutation(graphene.Mutation):
    class Arguments:
        name = graphene.String(required=True)
        num_licenses = graphene.Int(required=True)
        import_records_limit = graphene.Int(required=True)
        status = graphene.Int(required=True)
        max_failed_logins = graphene.Int(required=True)
        account_type = graphene.String(required=False)
        max_allowed_records = graphene.String(required=False)
        password_expiry = graphene.String(required=False)
        account_type = graphene.String(required=False)
        reinstated_notifications = graphene.String(required=False)
        saml_only = graphene.String(required=False)
        access_ip_range = graphene.String(required=False)

    account = graphene.Field(lambda: AccountObject)

    def mutate(self, info, **kwargs):
        settings = []
        for name, value in kwargs.items():
            if name not in baseproperties:
                settings.append(AccountSetting(name=name,value=value))

        account = Account(name=kwargs.get('name'), num_licenses=kwargs.get('num_licenses'),
                import_records_limit=kwargs.get('import_records_limit'), status=kwargs.get('status'),
                max_failed_logins=kwargs.get('max_failed_logins'), settings=settings, date_created=datetime.utcnow())
        db_session.add(account)
        db_session.commit()
        return CreateAccountMutation(account=account)

正如您在此处看到的,传递的不在基本属性中的附加属性将作为 AccountSetting 对象放置在设置中。这适用于 graphiQL:

mutation 
  createAccount(name: "Red Cross", numLicenses: 76, importRecordsLimit: 50000, maxFailedLogins: 20, status: 1, maxAllowedRecords: "50", passwordExpiry: "90", accountType: "fullservice", reinstatedNotifications: "1", samlOnly: "0", accessIpRange: "Test Rangate") 
    account 
      name
      settings 
        name
        value
      
    
  

但是这个突变文件不能编译:

const mutation =  graphql`
    mutation CreateAccountMutation(
        $name: String!, $numLicenses: Int!, $importRecordsLimit: Int!, $status: Int! 
        $maxFailedLogins: Int!, $maxAllowedRecords: String!, $passwordExpiry: String!,
        $accountType: String!, $reinstatedNotifications: String!, $samlOnly: String!, $accessIpRange: String!

        ) 
        createAccount(  name: $name, numLicenses: $numLicenses, importRecordsLimit: $importRecordsLimit, status: $status,
                        maxFailedLogins: $maxFailedLogins, maxAllowedRecords: $maxAllowedRecords, passwordExpiry: $passwordExpiry,
                        accountType: $accountType, reinstatedNotifications: $reinstatedNotifications, samlOnly: $samlOnly, accessIpRange: $accessIpRange
                    ) 
            account 
                name
                numLicenses
                importRecordsLimit
                status
                maxFailedLogins
                maxAllowedRecords
                passwordExpiry
                accountType
                reinstatedNotifications
                samlOnly
                accessIpRange
            
        
    
`;

export default (
    name,num_licenses,import_records_limit,status,
    maxFailedLogins,maxAllowedRecords,passwordExpiry,
    accountType,reinstatedNotifications,samlOnly,
    accessIpRange,  callback) => 

    const variables = 
        name,
        num_licenses,
        import_records_limit,
        status,
        maxFailedLogins,
        maxAllowedRecords,
        passwordExpiry,
        accountType,
        reinstatedNotifications,
        samlOnly,
        accessIpRange,
    

    commitMutation(
        environment,
        
            mutation,
            variables,
            onCompleted: () => 
                callback()
            ,
            onError: err => console.error(err),
        ,
    )

我在这里做错了吗?还有其他方法吗?解决此问题的“正确”方法?

【问题讨论】:

【参考方案1】:

所以我在这里所做的(不确定这是否是正确的方法)是我在帐户对象中添加了其他列,尽管数据库中实际上没有这些列。编译通过了,但我不确定它是否能完全工作:

class Account(Base):
    __tablename__ = 'accounts'

    id = Column(Integer, primary_key=True)
    raw_id = Column('id', Integer, primary_key=True)
    name = Column(String(255), nullable=False)
    num_licenses = Column(Integer, nullable=False)
    import_records_limit = Column(Integer, nullable=False)
    max_failed_logins = Column(Integer, nullable=False)
    status = Column(Integer, nullable=False)
    employee_lists = relationship('EmployeeList')
    users = relationship('User')
    policies = relationship("Policy", secondary=accounts_policies, back_populates="accounts")
    settings = relationship('AccountSetting')
    date_created = Column(DateTime)
    account_type = Column(String(255), nullable=False)
    max_allowed_records = Column(String(255), nullable=False)
    password_expiry = Column(String(255), nullable=False)
    account_type = Column(String(255), nullable=False)
    reinstated_notifications = Column(String(255), nullable=False)
    saml_only = Column(String(255), nullable=False)
    access_ip_range = Column(String(255), nullable=False)

编辑: 出现以下错误不起作用:

"errors": [
    
      "message": "(pymysql.err.InternalError) (1054, \"Unknown column 'max_allowed_records' in 'field list'\")\n[SQL: INSERT INTO accounts (name, num_licenses, import_records_limit, max_failed_logins, status, date_created, max_allowed_records, password_expiry, account_type, reinstated_notifications, saml_only, access_ip_range) VALUES (%(name)s, %(num_licenses)s, %(import_records_limit)s, %(max_failed_logins)s, %(status)s, %(date_created)s, %(max_allowed_records)s, %(password_expiry)s, %(account_type)s, %(reinstated_notifications)s, %(saml_only)s, %(access_ip_range)s)]\n[parameters: 'name': 'Blue Green', 'num_licenses': 100, 'import_records_limit': 5000, 'max_failed_logins': 20, 'status': 1, 'date_created': datetime.datetime(2019, 9, 3, 13, 24, 2, 354409), 'max_allowed_records': None, 'password_expiry': None, 'account_type': None, 'reinstated_notifications': None, 'saml_only': None, 'access_ip_range': None]\n(Background on this error at: http://sqlalche.me/e/2j85)"

【讨论】:

以上是关于在 Relay 中创建嵌套突变会引发未知字段的主要内容,如果未能解决你的问题,请参考以下文章

如何删除 Graphene Django 突变查询(中继)中的嵌套输入对象?

中继:有条件地在突变的胖查询中包含字段

中继突变中没有字段“clientMutationId”

从字典列表中创建嵌套的 json 对象

如何在BigQuery中创建嵌套字段和数组的数组

在创建模型的 GraphQL/Relay 突变中,有没有办法取回模型 ID?