Как добраться до первичного ключа объекта самообследования? - PullRequest
5 голосов
/ 10 августа 2010

Я пытаюсь создать универсальный метод, который будет извлекать элемент по его идентификатору:

public T GetByID(int id)
{
    return (T) context.GetObjectByKey(
        new System.Data.EntityKey(context.DefaultContainerName + "." +
             context.CreateObjectSet<T>().EntitySet.Name, 
             "ProductID", id));
}

В принципе, я могу вывести имя сущности из T, однако я понятия не имею, как выяснить, какой первичный ключ для сущности?

Ответы [ 3 ]

5 голосов
/ 11 августа 2010

Я закончил тем, что создал свой собственный атрибут и изменил шаблон T4, чтобы поместить этот атрибут над столбцом первичного ключа.Вот шаги, которые я предпринял:

  1. Добавьте следующее выше атрибута [DataMember] в шаблоне T4:

    <#if (ef.IsKey(edmProperty)) {#>    
    [PrimaryKeyAttribute]
    <#}#>
    
  2. СоздайтеPrimaryKeyAttribute:

    [AttributeUsage(AttributeTargets.Property)]
    public class PrimaryKeyAttribute : Attribute
    {}
    
  3. Введите вспомогательный метод для определения первичного ключа объекта:

    private string GetPrimaryKey<K>()
    {
        string primaryKey = string.Empty;
    
        PropertyInfo[] entityProperties = typeof(K).GetProperties();
    
        foreach (PropertyInfo prop in entityProperties)
        {
            object[] attrs = prop.GetCustomAttributes(false);
            foreach (object obj in attrs)
            {
                if (obj.GetType() == typeof(PrimaryKeyAttribute))
                {
                    primaryKey = prop.Name;
                    break;
                }
            }
        }
    
        if (string.IsNullOrEmpty(primaryKey))
            throw new Exception("Cannot determine entity's primary key");
    
        return primaryKey;
    }
    
  4. Наконец, напишите общий GetByIDкак таковой:

    public T GetByID(int id)
    {
        return (T)context.GetObjectByKey(new EntityKey(context.DefaultContainerName 
                                            + "." + context.CreateObjectSet<T>().EntitySet.Name
                                            , GetPrimaryKey<T>(), id));            
    }
    
3 голосов
/ 01 июня 2011
Here's another solution that uses the MetadataWorkspace...

1. Create a base DataAccess class with the following signature.

        public class DataAccessBase<TDataEntity> : IDisposable
            where TDataEntity : EntityObject

2. Create a method in DataAccessBase as the following...


    public TDataEntity GetByKey(object keyId)
            {
                // Get the entity key name
                var keyName = EntityContext.MetadataWorkspace
                                .GetEntityContainer(EntityContext.DefaultContainerName, DataSpace.CSpace)
                                .BaseEntitySets
                                .First(x => x.ElementType.Name == typeof(TDataEntity).Name)
                                .ElementType
                                .KeyMembers
                                .Select(key => key.Name)
                                .FirstOrDefault();

                // Get the Entity Set name
                var entitySet = (from container in EntityContext.MetadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace)
                                 from set in container.BaseEntitySets.OfType<EntitySet>()
                                 where set.ElementType.Name == typeof(TDataEntity).Name
                                 select set).FirstOrDefault();


                // Create qualified type name for entity
                string qualifiedTypeName = String.Format("{0}.{1}", EntityContext.DefaultContainerName, entitySet.Name);

                // Create the EntityKey
                EntityKey entityKey = new EntityKey(qualifiedTypeName, keyName, keyId);

                // Return object by it's entity key
                return (TDataEntity)EntityContext.GetObjectByKey(entityKey);
            }
3 голосов
/ 10 августа 2010

Вот фрагмент, который у меня есть .. Надеюсь, это поможет.Теперь, когда я смотрю на это, я думаю, что мог бы улучшить и это.

    _qualifiedTypeName = _context.DefaultContainerName + "." + _baseTypeName;
    Type baseType = GetBaseType(typeof(T));
    _baseTypeName = baseType.Name.ToString();

    PropertyInfo[] entityProperties = baseType.GetProperties();
    List<string> keyList = new List<string>();

    foreach (PropertyInfo prop in entityProperties) 
    {
      object[] attrs = prop.GetCustomAttributes(false);
      foreach (object obj in attrs)                
      {
        if (obj.GetType() == typeof(EdmScalarPropertyAttribute))
        {
          EdmScalarPropertyAttribute attr = (EdmScalarPropertyAttribute)obj;
          if (attr.EntityKeyProperty) keyList.Add(prop.Name);
         }
       }
    }
    if (keyList.Count > 0)
    {
      _keyName = keyList[0];
    }

, а затем вы вернете его как:

EntityKey key = new EntityKey(_qualifiedTypeName, _keyName, id);
return (T)_context.GetObjectByKey(key);

и похоже, что я получил выше здесь: http://blog.vascooliveira.com/how-to-check-for-an-entity-objects-entitykey-properties/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...