使用ASP.NET MVC和实体框架在SQL Server中保存数据时出现错误。该错误表明它无法插入具有空主键的数据。我已经将IsIdentity
设置为自动递增1。
这是代码:
public ActionResult Index(User user)
{
if (ModelState.IsValid)
{
if (user.UserId != 0)
db.Entry(user).State = EntityState.Modified;
else
user.IsActive = true;
db.Users.Add(user);
db.SaveChanges();
}
return View(user);
}
答案 0 :(得分:1)
这是SQL事情。如果您有一个包含列ID
和Name
的表,其中ID
是主键,并带有标识设置以及NOT NULL
和UNIQUE
约束,则插入语句必须如下所示:
INSERT INTO [table] (name) values ('Vivek')
这将自动处理ID列。但是,这将失败:
INSERT INTO [table] (ID, name) values (NULL, 'Vivek')
它试图告诉数据库您希望ID
列的值为NULL
。当然,由于NOT NULL
约束,这失败了。它与第一个选项不同,在第一个选项中,允许数据库使用标识来设置ID
列的值。
现在继续(大概)C#代码。这里有一个User
对象,它还没有ID
值,因为您只是在创建它。此User
类型(未共享,所以我只能猜测)可能具有一个简单的int
的{{1}}值,并且此int尚未初始化(意味着该值是{{ 1}},即ID
)。现在,您要插入记录。 Linq将生成类似于以下内容的SQL语句:
default(int)
但是在过去的某个地方,您运行了相同的代码,并且具有相同的0
值,因此表中已经有了该ID值的另一条记录。这将导致UNIQUE约束失败,并且SQL Server(正确地)拒绝了SQL语句。
要解决此问题,我们将通过更改此模型上的ID值以使用INSERT INTO [table] (ID, name) values (0, 'Vivek')
类型来开始。我知道您可能不希望到处都这样,因此,如果有帮助,您实际上可以在此处使用其他类(0
)。这将为生成的SQL中的ID列提供一个真正为空(NULL)的值。
但是现在我们遇到了一个新问题:我们最后得到了一个插入,就像我的第二个示例一样。我们看到这还不够;我们需要告诉linq根本不要在生成的SQL中使用该列。您可以通过从特殊的int?
类中完全删除ID属性来完成此操作。
但是我们可以做得更好。 Linq允许我们使用称为attributes的东西来装饰属性,这些属性会影响生成的SQL。您可以在这里告诉它如何处理ID列:
NewUser
此可以与现有的NewUser
类一起使用,而无需创建全新的类型。