C#,实体框架,自增

27

我正在学习使用 VC# 2010 下的 Entity Framework。

我创建了一个简单的表格,用于学习目的,其中一个字段是“id”,类型为整数,标识设置为 true。我从该表生成了实体数据模型,并将其与 dataGridView 连接起来。问题是它不会自动递增 - 每个插入的行都希望 id=0(这显然是不可能的,因为 id 必须唯一)

我做错了什么?我应该如何配置 EF 或 SQL 数据库本身?

5个回答

40

检查你的EDMX模型,确保自增字段的StoreGeneratedPattern属性设置为"Identity"。这样,EF就知道自动编号是由数据库处理的。

这里有更好的解释:使用Entity Framework进行自动编号


通常来说,从VS2010生成的部分中,您将不得不在XML的顶部大块中设置StoreGenerated值。除非您更改此设置,否则会出现多个主键,因为EF会为您生成ID作为0。 - Rangoric
5
他们还没有修复这个普遍存在的漏洞,真是太疯狂了。这已经是第四版了,EF团队加油啊! - arviman
1
很多时候,人们会忘记给列标记一个Identity和自增值。但EF可以从数据库中获取这些信息。 - arviman
这是针对VS2010SP1设计师的热修复补丁,可能会对您有所帮助:http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=37957 - Davut Gürbüz

3

仅通过将实体添加到实体集中并不会设置和递增标识符...直到调用context.SaveChanges()时,实体才被真正保存到数据库中...

db.AddToUserSet(user);//Added to EF entity collection
db.SaveChanges();//INSERT executed in db, Identity set and incremented.

9
问题在于,在添加多行后调用SaveChanges时,它会抛出有关重复主键的异常... - migajek

2

我曾经遇到过类似的问题,这个问题出现在EF6中(在没有事务的情况下,EF4可以工作,因为EF4使用了正确范围的隐式事务)。

仅仅创建一个新实体并保存它并不能解决我的问题(请看其他答案的评论,他们也有类似的问题,只使用dc.SaveChanges()进行自动更新)。

请考虑以下代码(CustomerId是带有自增的主键):

public void UpdateCustomer(string strCustomerName, string strDescription)
{
  using (var transaction = CreateTransactionScope())
  {
    MyCustomer tbl=null;
    Func<MyCustomer, bool> selectByName=(i => i.CustomerName.Equals(strCustomerName));
    var doesRecordExistAlready = dc.MyCustomers.Any(selectByName); 
    if (doesRecordExistAlready) 
    {
        // Updating
        tbl=dc.MyCustomers.Where(selectByName).FirstOrDefault();        
        tbl.Description=strDescription;
    }
    else
    {
        // Inserting
        tbl=new MyCustomer(); 
        var maxItem=
           dc.MyCustomers.OrderByDescending(i => i.CustomerId).FirstOrDefault();
        var newID = maxItem==null ? 1 : maxItem.CustomerId+1;
        tbl.CustomerId=newID;
        tbl.CustomerName=strCustomerName; 
        tbl.Description=strDescription;
        dc.MyCustomers.AddObject(tbl);      
    }
    dc.SaveChanges(); // save all changes consistently          
    transaction.Complete(); // commit
  }
}

创建正确的事务上下文的辅助函数为:

// creates the right transaction scope
public static System.Transactions.TransactionScope CreateTransactionScope() 
    // needs to add ref: System.Transactions
 { 
    var transactionOptions = new TransactionOptions 
    { 
        IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted,
        Timeout = new TimeSpan(0,0,10,0,0) //assume 10 min is the timeout time
    }; 
    var scopeOption=TransactionScopeOption.RequiresNew;
    var scope = new System.Transactions.TransactionScope(scopeOption, 
               transactionOptions); 
    return scope;
} 

关键在于允许读取未提交的内容 - 因此您可以查询最大ID并将1添加到ID。我无法实现的是让SQL服务器自动生成ID,因为EF不允许在创建时省略CustomerId

要了解有关事务范围的更多信息,请查看此处


2

在尝试读取自增Id值之前,请确保将实体保存回数据库。

只有在第一次保存到数据库时,Id才会被自动递增设置。


3
问题在于,当添加多行数据后调用SaveChanges时,它会抛出有关重复主键的异常。 - migajek
@vic - 有趣。你确定它是在自增键表的插入操作上失败了吗? - Justin Niessner

2

是的,LINQ to SQL 的行为也是如此。在保存到数据库之前,id 不会被设置。在此之前,所有的 id 都将为零(正如你已经看到的那样)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接