ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.25k stars 745 forks source link

Mutation with EF model object as parameter #5022

Open mscrocdile opened 2 years ago

mscrocdile commented 2 years ago

Is there an existing issue for this?

Describe the bug

This

public Customer AddCustomer(Customer customer)
        {
            ctx.Customers.Add(customer);
            ctx.SaveChanges();
            return customer;
        }

results to that graphql mutation query requires customer.id which is primary key. mutation { addCustomer(customer: {email:"abc@cde.ef",name:"xy"}) { id, name } } In this case i don't want to pass Customer.ID at all. Is there any workaround (without need to create new input type) or it is simply not possible?

Steps to reproduce

  1. Create mutation function with any EF model with primary key as a parameter.
  2. create mutation query
  3. Error that ID is required parameter appears.

Relevant log output

No response

Additional Context?

No response

Product

Hot Chocolate

Version

12.8.1

rhyshamilton commented 2 years ago

As per the docs, it is best practice for Mutations to contain a single argument called Input.

However, you don’t need to create these manually!

HotChocolate allows you to opt in to the AddMutationConventions when configuring your GraphQL server.

service
    .AddGraphQLServer()
    .AddMutationConventions(applyToAllMutations: true)

(The applyToAllMutations: true is optional, but I personally recommend it)

Then, all you’d need to do is adjust your method to only include the properties you want (e.g – email and name)

public Customer AddCustomer(string email, string name, ...)

If you prefer, you can still always create your own inputs, but with the AddMutationConventions you don’t necessarily have to.

Hope this helps :)

mscrocdile commented 2 years ago

Conventions... clear. However if i want to do this: public Customer AddCustomer(Customer c) and public Customer UpdateCustomer(Customer c) In mutation query I thought it is somehow possible that UpdateCustomer expect Customer.ID and in AddCustomer doesn't. Simply modify EF model or tell it to framework somehow. To avoid parameters duplications or creating similar models outside EF. Thank you

cts-tradeit commented 2 years ago

1) Define InputObject with generic argument YourEntityClass class and mark field id as nullable (in InputObject's field descriptor, entity's id property stays int or other nonnullable type). However you will have to manually validate in each mutation that id is or is not filled. You can even add the type attribute to your entity's property but you are polluting entity model with HC attributes.

OR

2) Create two classes UpdateYourEntityInput and CreateYourEntityInput which both inherit your entity and mark property id in create input ignored by attribute (not sure if attribute exists) or using option 1. This produces two separate input types which are both assignable to YourEntity in C# and can be directly added to EFC (which recognises that it's suppose to save it as parent type as EFC scans inheritance for non-configured types to find configured type). You can just define two InputTypes with generic argument YourEntity instead of creating dedicated input dtos as long as you manually set different name to each input (by default they use name equivalent to the type used as generic argument) and mark field id as ignored in one.

OR

3) Use option 1 (with nullable field) and have only one mutation saveYourEntity and use EFC's method Attach() (not sure if it's this one) to decide whether perform add or update.