Как реализовать универсальный метод GetById с использованием Entity Framework 4 и шаблона репозитория?

У меня есть общий репозиторий, и я хотел бы реализовать универсальный метод GetById. Это мой интерфейс репозитория:

public interface IRepository<T> where T : EntityObject  
{
    void Add(T entity);
    void Delete(int id);
    void Delete(T entity);
    IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
    T SingleOrDefault(Expression<Func<T, bool>> predicate);
    IEnumerable<T> GetAll();
    T GetById(int id);
    void Save();
    T Single(Expression<Func<T, bool>> predicate);
}

Я использую Entity Framework 4.1. Во многих найденных мною решениях использовался абстрактный базовый класс интерфейса для класса IEntity, от которого сущности должны наследовать для выполнения поиска по идентификатору.

Вместо того, чтобы реализовывать интерфейс для всех моих классов, я пытался использовать этот фрагмент кода:

T entity = _objectSet.Where(
    x => x.EntityKey.EntityKeyValues
          .Select(v => v.Value.Equals(id)).Count() == 1).First();

Однако при попытке использовать метод я получаю исключение:

The specified type member 'EntityKey' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Может кто-нибудь сказать мне, как я могу заставить это работать?

Обновление 1

Члены _objectContext и _context объявляются следующим образом:

private readonly ObjectContext _context;
private readonly IObjectSet<T> _objectSet;

Спасибо.


person b3n    schedule 03.04.2011    source источник
comment
Отметьте этот ответ: stackoverflow.com/questions/5273416/ Он содержит именно то, что вы ищете.   -  person Ladislav Mrnka    schedule 03.04.2011


Ответы (2)


Из этого вопроса Как получить имя ключа объекта ObjectSet ‹T›?, можно немного схитрить и использовать ESQL.

    public T GetById(int id)
    {

        var keyPropertyName = _objectSet.EntitySet.ElementType.KeyMembers[0].ToString();        

        T entity = _objectSet.Where("it." + keyPropertyName + "=" + id).First();
        return entity;

    }

Я включил в метод весь необходимый код, очевидно, вы хотите его немного реорганизовать, но он должен сработать для вас.

person Rob    schedule 03.04.2011
comment
Я добавил некоторую информацию выше, поскольку мой ObjectSet не предоставляет свойство Context или EntitySet. - person b3n; 03.04.2011
comment
Неважно, изменение IObjectSet на ObjectSet помогло. Отправлю, если он будет работать позже. - person b3n; 03.04.2011
comment
А что, если мы точно не знаем тип данных id. Это может быть int, Int16, Int64, long и т. Д. Каким будет лучший подход для динамического преобразования его в тип данных Id объекта? - person razp26; 11.09.2015
comment
Мы на самом деле просто используем его как строку, поэтому вы можете изменить тип идентификатора на что угодно, если метод ToString () будет точно отражать значение, вы должны быть в хорошей форме. - person Rob; 12.11.2015

Для тех, кому «повезло» работать в VB.net, и вы изо всех сил пытаетесь получить рабочий пример:

Imports System.Runtime.CompilerServices
Imports System.Data.Objects
Imports System.Collections.Generic

Public Module ObjectSetExtension

    <Extension()>
    Public Function GetById(Of T As Class)(self As ObjectSet(Of T), Id As Integer)
        Dim keyPropertyName = self.EntitySet.ElementType.KeyMembers(0).ToString()
        Dim entity As T = self.Where("it." & keyPropertyName & "=" & Id).First
        Return entity
    End Function

    <Extension()>
    Public Function GetById(Of T As Class)(self As ObjectSet(Of T), Id As Guid)
        Dim keyPropertyName = self.EntitySet.ElementType.KeyMembers(0).ToString()
        ' 'note the "GUID" in the string. DO NOT REMOVE!
        Dim entity As T = self.Where("it." & keyPropertyName & "=GUID '" & Id.ToString() & "'").First
        Return entity
    End Function

End Module
person Atron Seige    schedule 19.02.2014