2010-06-02 36 views
11

Tôi đang cố gắng tạo một phương pháp chung bằng EF4 để tìm khóa chính của một đối tượng.Entity Framework 4: Cách tìm khóa chính?

dụ

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

Để cung cấp thêm thông tin Tôi đang làm việc trên các Tekpub Starterkit và bên dưới là lớp tôi đang cố gắng đứng dậy và chạy

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

Trả lời

15

Vì vậy, cuối cùng tôi đã có thể tìm hiểu cách làm việc này. Tôi ước tôi đã không mất liên kết tới blog mà tôi đã đọc tối qua vì tôi không viết mã.

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

Tôi hy vọng điều này sẽ giúp người khác. Tất cả những gì tôi có thể nói là nó phải rõ ràng hơn một chút về cách làm điều này.

+1

Tôi đoán nó là từ: http://www.guerrillasyntax.com/index.php/2010/04/24/linq-to-entity-generic-repository/ –

+0

Đó là nó. Tìm kiếm tốt –

+3

Về mặt kỹ thuật không hợp lệ, vì điều này sẽ trả lại kết quả không chính xác nếu có khóa chính kết hợp. – Nuzzolilo

15

Có một tài sản trên mỗi Thực thể EF4 được gọi là EntityKey có chứa một mảng là EntityKeyValues (mảng có trong trường hợp khóa ghép).

Bạn có thể tham khảo điều này trực tiếp trên cá thể tổ chức của bạn hoặc tạo phương thức trợ giúp chung để thực hiện việc này trong phần trình bày. Nếu tôi có thể thử nghiệm một số mã mẫu, tôi sẽ đăng nó lên đây.

Sửa: Các EntityKeyValue là một KeyValuePair<TKey, TValue> nơi key là trường khóa chính của thực thể và value là giá trị đi kèm.

Ví dụ: tôi có một thực thể được gọi là Company có khóa chính là trường Symbol.

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

Trong hộp cát của tôi, tôi nhận thấy thuộc tính này là null khi tôi tạo đối tượng trong mã. Nhưng một khi tôi đọc thực thể từ cơ sở dữ liệu, nó đã được phổ biến một cách chính xác. Vì vậy, có vẻ như khái niệm EF4 của khóa chính chỉ được phát khi nó chạm vào cơ sở dữ liệu. Mặc dù, bạn được tự do đặt nó rõ ràng trước thời hạn, nếu bạn muốn.

+0

Bạn cũng có thể thử context.Companies.EntitySet.ElementType.KeyMembers –

+2

làm thế nào mà tôi không có tài sản đó? –

+4

Trong trường hợp có ai đến muộn này ...EntityKey chỉ tồn tại trên các đối tượng kế thừa từ EntityObject; những người duy nhất làm điều đó là công cụ mô hình đầu tiên. –

2

điều này có vẻ không cần thiết lâu? Tôi đã có nhu cầu tương tự, và sử dụng những gợi ý ở trên (bởi SethO và denis_n), tôi đang sử dụng:

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

Hope this helps bất cứ ai quan tâm đến

+2

Tên cột có giá trị "nhập" không? –

+0

@ rana bạn giả sử chỉ có một cột là khóa chính –

1

tôi giả sử nhiều người dừng lại qua đường bưu điện này chỉ bằng cách tìm "Khuôn khổ thực thể như thế nào để tìm khóa chính?" bất kể phiên bản EF (như tôi). Vì vậy, tôi muốn đề cập rằng với EF 6.1, bạn cũng có thể tạo một phương thức mở rộng để lấy khóa chính. Sau đây là ví dụ và hoạt động hoàn toàn tốt.

PS: Tôi không chắc chắn 100%, nếu điều đó có thể hoạt động với các phím tổng hợp và phức hợp tho.

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

Các vấn đề liên quan