2010-07-06 5 views
23

J'apprends Entity Framework en VC# 2010.C#, Entity Framework, incrémentation automatique

J'ai créé un tableau simple à des fins d'apprentissage, l'un des champs est un entier de type "id", l'identité définie sur true . J'ai généré Entity Data Model à partir de cette table et l'ai connecté avec dataGridView. Le problème est qu'il ne s'incrémente pas automatiquement - chaque ligne insérée veut être id = 0 (ce qui est impossible bien sûr puisque id doit être unique)

Qu'est-ce que je fais de mal? Comment dois-je configurer EF ou SQL db lui-même?

Répondre

35

Vérifiez dans votre modèle EDMX que l'attribut StoreGeneratedPattern du champ autoincrement est défini sur "Identity". De cette manière, EF sait que les numéros automatiques sont gérés par la base de données.

Ici cela est mieux expliqué: Autonumber with Entity Framework

+0

Ouais généralement à partir des pièces générées VS2010 vous devrez définir la valeur StoreGenerated dans le gros bloc supérieur de xml. Vous obtenez plusieurs clés primaires car, sauf si vous modifiez cela, EF génère l'ID pour vous, comme 0. – Rangoric

+5

C'est fou qu'ils n'aient pas encore résolu ce bug omniprésent. C'est la version 4, venez sur l'équipe EF! – arviman

+1

Souvent, les gens oublient de marquer la colonne avec une valeur d'incrément d'identité et automatique. EF récupère cela de la base de données. – arviman

1

Assurez-vous de sauvegarder vos entités dans la base de données avant d'essayer de lire la valeur de l'ID auto-incrémentée.

Votre identifiant ne sera pas défini par incrémentation automatique jusqu'à la première sauvegarde dans la base de données.

+2

le problème est que, tout en appelant SaveChanges (après l'ajout de plusieurs lignes), il lance une exception au sujet de clé primaire en double ... – migajek

+0

@vic - Intéressant. Êtes-vous sûr que cela échoue sur l'insertion pour la table de touches Auto-Incrémented? –

1

Oui. LINQ to SQL se comporte de la même manière. L'ID ne sera pas défini tant qu'il n'est pas enregistré dans la base de données. Jusqu'à ce que vous le fassiez, tous les identifiants seront nuls (comme vous l'avez déjà vu).

2

L'identité est pas définie et incrémenté en ajoutant simplement à l'ensemble des entités ... L'entité n'est pas réellement enregistrée dans la db jusqu'à ce que vous appelez context.SaveChanges() ...

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

le problème est que tout en appelant SaveChanges (après avoir ajouté plusieurs lignes) il jette une exception à propos de la clé primaire dupliquée ... – migajek

0

J'ai eu des problèmes similaires qui se sont produits dans EF6 (travaillèrent à EF4 sans transactions, EF 4 utilisé les transactions implicites avec la portée droite).

Juste en créant une nouvelle entité et en l'enregistrant n'a pas aidé dans mon cas (voir les commentaires des autres réponses, ils ont eu des problèmes similaires avec l'utilisation dc.SaveChanges() uniquement pour la mise à jour automatique).

Consultez le code suivant (CustomerId est la clé primaire avec auto-incrément):

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 
    } 
} 

Et la fonction d'aide pour créer le bon contexte de transaction:

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

L'astuce est ici , pour permettre la lecture non validée - d'où vous pouvez interroger l'ID max et ajouter 1 à id. Ce que je n'ai pas réussi à faire est de laisser le serveur SQL générer l'ID automatiquement, car EF me permet de ne pas omettre le CustomerId lors de la création.

Pour en savoir plus sur la portée de la transaction, look here.