6

I have a generic repository and would like to implement a generic GetById method. This is my repository interface so far:

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

I am using the Entity Framework 4.1. Lots of the solutions I found were using an abstract base class of interface for an IEntity class which the entities have to inherit from in order to perform the Id lookup.

Instead of having to implement an interface for all my classes I was trying to use this bit of code:

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

However when trying to use the method I receive an exception:

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

Could someone tell me how I can get this to work?

Update 1

The members _objectContext and _context are declared like this:

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

Thanks.

b3n
  • 3,805
  • 5
  • 31
  • 46
  • Check this answer: http://stackoverflow.com/questions/5273416/entity-framework-simple-generic-getbyid-but-has-differents-pk-name/5278684#5278684 It contains exactly what you are looking for. – Ladislav Mrnka Apr 03 '11 at 08:03

2 Answers2

6

From this question How to get ObjectSet<T>'s entity key name?, you can cheat a little and use ESQL.

    public T GetById(int id)
    {

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

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

    }

I've included all the needed code in the method, obviously you want to refactor it a little, but it should work for you.

Community
  • 1
  • 1
Rob
  • 1,320
  • 1
  • 8
  • 14
  • I've added some information above as my ObjectSet does not expose a property Context or EntitySet. – b3n Apr 03 '11 at 04:55
  • Nevermind, changing IObjectSet to ObjectSet did the trick. Will post if its working later. – b3n Apr 03 '11 at 05:06
  • What about if we don't know exactly the id data type. It could be int, Int16, Int64, long, etc. What would be the best approach for dynamically casting it to the entitie's Id data type? – razp26 Sep 11 '15 at 14:29
  • We're really just using it as a string here, so you can change the id type to anything as long as the ToString() method will accurately reflect the value, you should be in good shape. – Rob Nov 12 '15 at 17:00
0

For those who are "lucky" enough to work in VB.net and you are struggling to get a working example:

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
Atron Seige
  • 2,783
  • 4
  • 32
  • 39