2010-06-02 14 views
11

Sto provando a creare un metodo generico usando EF4 per trovare la chiave primaria di un oggetto.Entity Framework 4: Come trovare la chiave primaria?

esempio

public string GetPrimaryKey<T>() 
{ 
    ... 
} 

Per dare più informazioni sto lavorando fuori del Tekpub StarterKit e sotto è la classe che sto cercando di alzarsi e correre

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Data.Objects; 
using System.Data.Objects.ELinq; 
using System.Data.Linq; 
using Web.Infrastructure.Storage.EF4; 

namespace Web.Infrastructure.Storage { 
public class EFSession:ISession { 
    PuzzleEntities _db;//This is an ObjectContext 
    public EFSession() { 
     _db = new PuzzleEntities(); 
    } 

    public void CommitChanges() { 
     _db.SaveChanges(); 
    } 
    /// <summary> 
    /// Gets the table provided by the type T and returns for querying 
    /// </summary> 
    private ObjectSet<T> GetObjectSet<T>() where T:class { 
     return _db.CreateObjectSet<T>(); 
    } 

    private T GetByPrimaryKey<T>() where T: class 
    { 
     ..... 
    } 

    public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class{ 

     foreach (T item in All<T>().Where(expression)) 
     { 
      GetObjectSet<T>().DeleteObject(item); 
     } 
    } 

    public void Delete<T>(T item) where T : class { 
     GetObjectSet<T>().DeleteObject(item); 
    } 

    public void DeleteAll<T>() where T : class { 
     foreach(T item in All<T>()) 
     { 
      GetObjectSet<T>().DeleteObject(item); 
     } 
    } 

    public void Dispose() { 
     _db.Dispose(); 
    } 

    public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T:class { 
     return GetObjectSet<T>().SingleOrDefault(expression); 
    } 

    public IQueryable<T> All<T>() where T : class { 
     return GetObjectSet<T>().AsQueryable(); 
    } 

    public void Add<T>(T item) where T : class { 
     GetObjectSet<T>().AddObject(item); 
    } 
    public void Add<T>(IEnumerable<T> items) where T : class { 
     foreach (T item in items) 
     { 
      GetObjectSet<T>().AddObject(item); 
     } 
    } 
    public void Update<T>(T item) where T : class { 
     //nothing needed here 
    } 
} 
} 

risposta

15

Quindi sono finalmente riuscito a scoprire come farlo funzionare. Vorrei non aver perso il link al blog che ho letto ieri sera perché non ho scritto il codice.

public T GetByPrimaryKey<T>(int id) where T : class 
{ 
    return (T)_db.GetObjectByKey(new EntityKey(_db.DefaultContainerName + "." + this.GetEntityName<T>(), GetPrimaryKeyInfo<T>().Name, id)); 
} 

string GetEntityName<T>() 
{ 
    string name = typeof(T).Name; 
    if (name.ToLower() == "person") 
     return "People"; 
    else if (name.Substring(name.Length - 1, 1).ToLower() == "y") 
     return name.Remove(name.Length - 1, 1) + "ies"; 
    else if (name.Substring(name.Length - 1, 1).ToLower() == "s") 
     return name + "es"; 
    else 
     return name + "s"; 
} 

private PropertyInfo GetPrimaryKeyInfo<T>() 
{ 
    PropertyInfo[] properties = typeof(T).GetProperties(); 
    foreach (PropertyInfo pI in properties) 
    { 
     System.Object[] attributes = pI.GetCustomAttributes(true); 
     foreach (object attribute in attributes) 
     { 
      if (attribute is EdmScalarPropertyAttribute) 
      { 
       if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty == true) 
        return pI; 
      } 
      else if (attribute is ColumnAttribute) 
      { 

       if ((attribute as ColumnAttribute).IsPrimaryKey == true) 
        return pI; 
      } 
     } 
    } 
    return null; 
} 

Spero che questo aiuti qualcun altro. Tutto quello che posso dire è che dovrebbe essere un po 'più chiaro su come farlo.

+1

Immagino che provenga da: http://www.guerrillasyntax.com/index.php/2010/04/24/linq-to-entity-generic-repository/ –

+0

È stato così. Buona ricerca –

+3

Tecnicamente non valido, poiché restituirà risultati errati se è presente una chiave primaria composita. – Nuzzolilo

15

C'è una proprietà su ogni Entità EF4 denominata EntityKey che contiene un array di EntityKeyValues (la matrice è presente in caso di chiave composta).

È possibile fare riferimento direttamente all'istanza dell'entità o creare un metodo di supporto generico che funzioni sotto le copertine. Se riesco a testare un codice di esempio, lo posterò qui.

Edit: L'EntityKeyValue è un KeyValuePair<TKey, TValue> dove il key è il campo chiave principale del soggetto e la value è il valore associato.

Es., Ho un'entità denominata Company la cui chiave primaria è il campo Symbol.

var firstCompany = (from c in context.Companies select c).FirstOrDefault(); 
var kvp = firstCompany.EntityKey.EntityKeyValues[0]; 
// kvp shows {[Symbol, FOO]} 

Nel mio sandbox, ho notato questa proprietà era null quando ho creato l'entità in codice. Ma una volta che ho letto l'entità dal database, è stata compilata correttamente. Quindi, sembra che il concetto EF4 di una chiave primaria entri in gioco solo quando raggiunge il database. Sebbene tu sia libero di impostarlo esplicitamente in anticipo, se lo desideri.

+0

Si può anche provare context.Companies.EntitySet.ElementType.KeyMembers –

+2

come mai non ho la proprietà? –

+4

Nel caso qualcuno venga a questo ritardo ...EntityKey esiste solo sugli oggetti che ereditano da EntityObject; gli unici che lo fanno sono roba di primo modello. –

2

questo sembra inutilmente lungo? ho avuto lo stesso bisogno, e utilizzando i suggerimenti di cui sopra (per Setho e denis_n), io sto usando:

 //get the primary key field name and location for the table 
     var primaryFieldName = entry.EntitySet.ElementType.KeyMembers[0].Name ; 
     int primaryFieldLocation = entry.CurrentValues.GetOrdinal(primaryFieldName); 
     //gets the value pair for the primary key (returns field name + value) 
     var primaryField = entry.EntityKey.EntityKeyValues[primaryFieldLocation]; 
     String primaryFieldValue = primaryField.Value.ToString(); 

Spero che questo aiuti chiunque sia interessato

+2

Il nome della colonna del valore di "immissione" è? –

+0

@rana si suppone che solo una colonna sia una chiave primaria –

1

presumo molte persone si fermano per questo post semplicemente cercando "Entity framework come trovare la chiave primaria?" indipendentemente dalla versione EF (come me). Quindi volevo dire che con EF 6.1, puoi anche creare un metodo di estensione per ottenere la chiave primaria. Segue l'esempio e funziona perfettamente.

PS: Non sono sicuro al 100%, se funzionasse con i tasti compositi e composti.

using System; 
using System.Data.Entity; 
using System.Data.Entity.Core.Metadata.Edm; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 

namespace System.Data.Entity 
{ 
    public static class DbContextExtensions 
    { 
     public static string[] GetKeyNames<TEntity>(this DbContext context) 
      where TEntity : class 
     { 
      return context.GetKeyNames(typeof(TEntity)); 
     } 

     public static string[] GetKeyNames(this DbContext context, Type entityType) 
     { 
      var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; 

      // Get the mapping between CLR types and metadata OSpace 
      var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace)); 

      // Get metadata for given CLR type 
      var entityMetadata = metadata 
        .GetItems<EntityType>(DataSpace.OSpace) 
        .Single(e => objectItemCollection.GetClrType(e) == entityType); 

      return entityMetadata.KeyProperties.Select(p => p.Name).ToArray(); 
     } 
    } 
} 

Original Source

Problemi correlati