3

When I call DbSet.FirstOrDefault() by passing a predicate that compares generic type TId, I get the following exception:

unable to create a constant value of type 'system.object'. only primitive types or enumeration types are supported in this context.

Interface for type being queried:

interface IEntity<TId>
{
    TId id { get; set; }
}

The exception is thrown here:

public virtual TEntity Get<TEntity, TId>(TId id) where TEntity : class, IEntity<TId>
{
    return dbContext.Set<TEntity>().FirstOrDefault(e => e.Id.Equals(id));
}

The function will only work if TId is constrained as struct. How can I include string as supported type? If it's not possible, is it possible to accomplish the task a different way?

user845279
  • 2,794
  • 1
  • 20
  • 38

2 Answers2

2

This will work for strings too:

public virtual TEntity Get<TEntity, TId>(TId id) 
    where TEntity : class, IEntity<TId>
    where TId: IEquatable<TId>
{
    return dbContext.Set<TEntity>().FirstOrDefault(e => e.Id.Equals(id));
}
UserControl
  • 14,766
  • 20
  • 100
  • 187
  • How can i extend it to work for arrays of these primitives too? Ex: int[] and string[]. Thanks. – user845279 Feb 02 '17 at 16:39
  • I don't think you can. Equality for sets (RDBMSs have no concept of arrays) is too broad and there is no direct `==`-like support for it in SQL. Consider for example `[1,2]` and `[2,1]`. Are they equal to you? Is ordering important? What about `[null, 1]` and `[null,1]`? Do you care about ternary logic here or not, etc. – UserControl Feb 02 '17 at 22:20
  • I'm working with MS Sql which has Binary[] type. It gets converted to System.Byte[]. – user845279 Feb 02 '17 at 22:33
2

You can simply use Find method:

public virtual TEntity Get<TEntity, TId>(TId id) where TEntity : class, IEntity<TId>
{
    return dbContext.Set<TEntity>().Find(id);
}
Slava Utesinov
  • 13,410
  • 2
  • 19
  • 26