How to implement generic GetById() where Id can be of various types
Solution 1
You should remove the constraint on TId from your Repository
class
public abstract class Repository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : class, IEntity<TId>
{
public virtual TEntity GetById(TId id)
{
return context.Set<TEntity>().Find(id);
}
}
Solution 2
public interface IEntity<TId> where TId : class
{
TId Id { get; set; }
}
The where TId : class
constraint requires every implementation to have a Id which derives from object which is not true for value types like int.
Thats what the error message tells you: The type 'int' must be a reference type in order to use it as parameter 'TId' in the generic type of method IEntity
Just remove the constraint where TId : class
from IEntity<TId>
Solution 3
To your question:
I am trying to implement a generic GetById(T id) method which will cater for types which may have differing ID types. In my example, I have an entity which has an ID of type int, and one of type string.
public virtual TEntity GetById<TId>(TId id)
{
return context.Set<TEntity>().SingleOrDefault(x => x.Id == id);
}
For generic parameter, just make a generic method like above
Related videos on Youtube
Tomuke
Updated on June 22, 2022Comments
-
Tomuke almost 2 years
I am trying to implement a generic
GetById(T id)
method which will cater for types which may have differing ID types. In my example, I have an entity which has an ID of typeint
, and one of typestring
.However, I keep getting an error and I have no idea why:
The type 'int' must be a reference type in order to use it as parameter 'TId' in the generic type of method IEntity
Entity Interface:
To cater for my domain models which can have Id's of type
int
orstring
.public interface IEntity<TId> where TId : class { TId Id { get; set; } }
Entity Implementations:
public class EntityOne : IEntity<int> { public int Id { get; set; } // Other model properties... } public class EntityTwo : IEntity<string> { public string Id { get; set; } // Other model properties... }
Generic Repository Interface:
public interface IRepository<TEntity, TId> where TEntity : class, IEntity<TId> { TEntity GetById(TId id); }
Generic Repository Implementation:
public abstract class Repository<TEntity, TId> : IRepository<TEntity, TId> where TEntity : class, IEntity<TId> where TId : class { // Context setup... public virtual TEntity GetById(TId id) { return context.Set<TEntity>().SingleOrDefault(x => x.Id == id); } }
Repository Implementations:
public class EntityOneRepository : Repository<EntityOne, int> { // Initialise... } public class EntityTwoRepository : Repository<EntityTwo, string> { // Initialise... }
-
D Stanley about 8 yearsWhy are you restricting
TId
toclass
types? That won't work withint
(the error message makes that pretty clear).class
means "reference type" in generic constraints.
-
-
Tomuke about 8 yearsThis suggestion resolves the reference type error, however, I am now getting an
Operator == cannot be applied to operands of type TId and TId
error when trying to perform the match by Id -
myhrmans about 6 yearsfor the
.SingleOrDefault(x=>x.Id == id)
error, you could also use.SingleOrDefault(x=>x.Id.Equals(id))