web-dev-qa-db-fra.com

Comment générer et incrémenter automatiquement un identifiant avec Entity Framework

Révisé article entier.

J'essaie de publier le JSON suivant POST via Fiddler:

{Username:"Bob", FirstName:"Foo", LastName:"Bar", Password:"123", Headline:"Tuna"}

Cependant, je reçois cette erreur:

Message "Cannot insert the value NULL into column 'Id', table 'xxx_f8dc97e46f8b49c2b825439607e89b59.dbo.User'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated." string

Cependant, si j'envoie manuellement un ID aléatoire avec la demande, tout va bien. Ainsi:

{Id:"1", Username:"Bob", FirstName:"Foo", LastName:"Bar", Password:"123", Headline:"Tuna"}

Pourquoi Entity Framework ne génère-t-il pas et n'incrémente-t-il pas automatiquement les ID? Ma classe POCO est la suivante:

public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public string Id { get; set; }
    public string Username { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string Headline { get; set; }
    public virtual ICollection<Connection> Connections { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
    public virtual ICollection<Phonenumber> Phonenumbers { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
    public virtual ICollection<Position> Positions { get; set; }
}

public class Connection
{
    public string ConnectionId { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
}

public class Phonenumber
{
    public string Id { get; set; }
    public string Number { get; set; }
    public int Cycle { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

Voici la méthode du contrôleur. Lorsque je suis en mode débogage et que j'envoie la requête via Fiddler, il se rompt à db.SaveChanges(); et donne l'erreur vue un peu plus haut.

    // POST api/xxx/create
    [ActionName("create")]
    public HttpResponseMessage PostUser(User user)
    {
        if (ModelState.IsValid)
        {
            db.Users.Add(user);
            db.SaveChanges();

            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, user);
            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = user.Id }));
            return response;
        }
        else
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }
    }

Qu'est-ce qui ne va pas?

Solution

Modifiez plutôt string id en int et supprimez les annotations de données. A renommé l'ID en UserId, toujours selon la convention, et a apporté des modifications si nécessaire dans d'autres POCO pour correspondre aux modifications.

41
brk

C'est une conjecture :)

Est-ce parce que l'ID est une chaîne? Que se passe-t-il si vous le changez en int?

Je veux dire:

 public int Id { get; set; }
43
tymtam

Vous avez un mauvais design de table. Vous ne pouvez pas auto-incrémenter une chaîne, cela n'a aucun sens. Vous avez essentiellement deux options:

1.) changer le type d’ID en int au lieu de chaîne
2.) Non recommandé !!! - gérer l'auto-incrémentation par vous-même. Vous devez d’abord extraire la dernière valeur de la base de données, l’analyser dans l’entier, l’incrémenter et la relier à l’entité sous forme de chaîne. TRES MAUVAISE idée

La première option nécessite de changer chaque table qui a une référence à cette table, MAIS ça vaut le coup.

8
walther