如何使用 Entity Framework 生成和自动递增 Id

Posted

技术标签:

【中文标题】如何使用 Entity Framework 生成和自动递增 Id【英文标题】:How to generate and auto increment Id with Entity Framework 【发布时间】:2013-04-11 08:20:15 【问题描述】:

修订整个帖子。

我正在尝试通过 Fiddler 发布以下 JSON POST 请求:

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

但是我收到了这个错误:

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

虽然如果我手动发送一个随机 ID 以及请求,那么一切都很好。像这样:

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

为什么 Entity Framework 不生成并自动递增 Id?我的 POCO 类如下:

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; 

这里是控制器方法。在调试模式下,我通过 Fiddler 发送请求时,它会在 db.SaveChanges(); 处中断,并给出上面看到的错误。

    // 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);
        
    

怎么了?

解决方案

改为将字符串 ID 更改为 int 并删除数据注释。将 Id 重命名为 UserId,仍然遵循约定,并在其他 POCO 中进行必要的更改以与更改相匹配。

【问题讨论】:

当您逐步调试控制器时,您是否在 db.SaveChanges() 处收到错误?也许是实体验证错误? 【参考方案1】:

这是一个猜测:)

是不是因为ID是一个字符串?如果将其更改为 int 会发生什么?

我的意思是:

 public int Id  get; set; 

【讨论】:

我觉得自己很傻,但现在对我来说很明显应该是int。只是当我开始的时候,一切都是string,我有点忘记了。谢谢;) 另一个提示是 not 忘记字段/数据库列需要在模型中表示为 properties 而不仅仅是普通字段/成员。【参考方案2】:

你的桌子设计不好。您不能自动增加字符串,这没有任何意义。您基本上有两种选择:

1.) 将 ID 类型更改为 int 而不是字符串 2.) 不推荐!!! - 自己处理自动增量。您首先需要从数据库中获取最新值,将其解析为整数,将其递增并再次将其作为字符串附加到实体。非常糟糕的主意

第一个选项需要更改引用此表的每个表,但这是值得的。

【讨论】:

你说的完全正确,这是我的糟糕设计。感谢您的意见:) 回复:不推荐!!! - 我不同意这一点。数据库完成的自动增量意味着您必须点击数据库才能创建一个并不总是很好的记录。但这是另一个话题...... @Tymek,erm,无论哪种方式,您都必须访问数据库以确定下一个应该是哪个 Id。但是,如果您让数据库为您处理它,您只需将其他参数传递给 db,然后 db 在处理插入时为您计算值。如果您自己处理自动增量,则必须从中获取最新的 id在您实际发送查询以插入记录之前的数据库。这是一次额外的 db 之旅!更不用说当您的数据库一次被多个应用程序/用户访问时的情况,这真是一场噩梦。 @Tymek,我真的看不出这可能是个好主意。 @Tymek,是的,Id 可以是任何东西,但是如果您不先访问数据库进行检查,您怎么知道哪个 id 未被使用?它必须是独一无二的,所以你需要有一个机制来处理这个问题。情况越复杂,实现它就越痛苦,特别是在并发场景中(比如 ASP.NET,这个问题是关于什么的),你需要为所有同时访问你的数据库的用户处理这个问题。如果你创建一个 ID,它会被占用怎么办?你将它传递给数据库,你会得到一个错误。你告诉用户什么? “糟糕,我们生成了错误的 ID,让我们再试一次”??

以上是关于如何使用 Entity Framework 生成和自动递增 Id的主要内容,如果未能解决你的问题,请参考以下文章

如何获取Entity Framework生成的SQL语句

Entity Framework Core 是如何根据实体类生成模型的?

Entity Framework 5.0系列之自动生成Code First代码

Entity Framework Core是如何根据实体类生成模型的?

如何防止 Entity Framework Core 2.0 重命名生成类中的表和列(数据库优先)

如何转换 Entity Framework 6 来为我的模型生成 FluentAPI 定义,而不是数据注释? (我在 VS2015 中使用 MySQL)