EF-не может применить оператор '= = 'к операндам типа' TId ' и 'TId'
у меня есть этот общий класс, который использует Entity Framework 6.x.
public class GenericRepository<TEntity, TId> where TEntity, class, IIdentifyable<TId>
{
public virtual TEntity GetById(TId id)
{
using (var context = new DbContext())
{
var dbSet = context.Set<TEntity>();
var currentItem = dbSet.FirstOrDefault(x => x.Id == id);
return currentItem;
}
}
public virtual bool Exists(TId id)
{
using (var context = new DbContext())
{
var dbSet = context.Set<TEntity>();
var exists = dbSet.Any(x => x.Id == id);
return exists ;
}
}
}
и эти интерфейсы:
public interface IIdentifyable : IIdentifyable<int>
{
}
public interface IIdentifyable<out TId>
{
TId Id { get; }
}
и сущности, которые выглядят так:
public class CustomerEntity : IIdentifyable<int>
{
public string Name { get; set; }
public int Id { get;set; }
}
public class ProductEntity : IIdentifyable<Guid>
{
public string Name { get; set; }
public Guid Id { get;set; }
}
моя проблема в том, что он не компилируется. Я получаю эту ошибку:
не удается применить оператор'
==
' к операндам типа 'TId
' и 'TId
'
я попытался изменить его на x => Equals(x.Id, id)
, но тогда EF не может перевести его. Как это обойти?
я знаю, что могу использовать Find()
вместо FirstOrDefault
. Но мне это нужно больше, чем упомянутые выше методы. есть ли способ, которым я могу позволить EF сравнить TId
С TId
? TId
времени guid
и int
. Я уже видел вопросы ниже, но они не обрабатывают проблему, касающуюся перевода на SQL.
не может operator == применяться к общим типам в C#?
как решить оператор '!= 'не может быть применен к операндам типа' T ' и 'T'
2 ответов
это известная проблема с дженериками, которая обычно обрабатывается с помощью EqualityComparer<T>.Default
вместо ==
оператора. Однако этот подход не работает с LINQ для сущностей.
один из способов его решения-динамически построить предикат с помощью Expression
класс System.Linq.Expressions
пространство имен, как это:
public class GenericRepository<TEntity, TId> where TEntity: class, IIdentifyable<TId>
{
protected static Expression<Func<TEntity, bool>> EqualsPredicate(TId id)
{
Expression<Func<TEntity, TId>> selector = x => x.Id;
Expression<Func<TId>> closure = () => id;
return Expression.Lambda<Func<TEntity, bool>>(
Expression.Equal(selector.Body, closure.Body),
selector.Parameters);
}
}
и используйте его так:
dbSet.FirstOrDefault(EqualsPredicate(id));
или
dbSet.Any(EqualsPredicate(id));
etc.
обновление: вот еще один способ, который работает с EF.
добавьте следующее ограничение в GenericRepository
класс
where TId : IEquatable<TId>
и затем использовать Equals
метод
x => x.Id.Equals(id);
это компилируется только если вы ограничиваете TId
введите тип ссылки:
public class GenericRepository<TEntity, TId>
where TEntity: class, IIdentifyable<TId>
where TId: class
однако это может быть не подходит в вашем случае, поэтому вам придется создавать разные классы для поддержки значений GUID, int или long id.