1

I have the following model class:

public class Item
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "You must provide a name.")]
    [MaxLength(255)]
    public string Name { get; set; }
}

When doing GET operations I want to return the object with the Id property, so the user can know what ID to query for update or specific GET. However I DON'T want the client to be able to provide a value for the ID property when doing POST requests and want it to be generated by the database as part of the IDENTITY thing.

How would I achieve that?

3
  • 1
    What's your issue with your code? It does exactly what you want and if clients fill its Id on insert it will throw exception and you can return Bad Request to client Commented May 28, 2020 at 20:44
  • @ArmanEbrahimpour, IT DOES?! Let me check... Commented May 28, 2020 at 20:56
  • 2
    Because you configure your Id as AutoGenerated, your database will throw an exception when you try to insert record with custom Id Commented May 28, 2020 at 21:06

1 Answer 1

1

You cannot manually set the value of an Identity (Auto Increment) column.

Here, in the below example PurchaseId is an Identity column.

purchase.PurchaseId = 6;
_dbContext.Purchases.Add(purchase);
_dbContext.SaveChanges();

When saving changes to the database the EF Core throws Microsoft.EntityFrameworkCore.DbUpdateException with Cannot insert explicit value for identity column in table 'Purchases' when IDENTITY_INSERT is set to OFF. error.

So, by default, you cannot assign the value.

But this is not the issue here.

The bigger issue is that you are exposing the Domain classes to your client. This flaw in API design can lead to more than this problem.

You have to create a DTO e.g. CreateItemDTO whose only responsibility is to contain all the methods required to create an Item in the database.

The same way you should not expose Item class in the GET request. This leads to a problem when API related columns that are not for clients gets exposed. Create a GetItemDTO which would only contain information that is important for the GET request.

CreateItemDTO

public class CreateItemDTO
{
    [Required(ErrorMessage = "You must provide a name.")]
    [MaxLength(255)]
    public string Name { get; set; }
}

Read Exposing domain models over API for more information.

Sign up to request clarification or add additional context in comments.

3 Comments

But shouldn't the DTO also contain an ID property, so the client can know what is the ID of an object they want to update?
@Shrodinger That is why this DTO is called CreateItemDTO. The UpdateItemDTO would contain the {ID, Name}.
I know at basic level DTO for each endpoint may seem like overkill. But it will always help you when the requirement for each endpoint will change. Which IMO happens after the client starts to be mature.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.