本文介绍了EF - 不能将运算符'=='应用于'TId'和'TId'类型的操作数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public class GenericRepository< TEntity,TId>< p>我有这个通用类,它使用实体框架6.x。其中TEntity,class,IIdentifyable< TId> 
{
public virtual TEntity GetById(TId id)
{
using(var context = new DbContext())
{
var dbSet = context。设置< TEntity>();
var currentItem = dbSet.FirstOrDefault(x => x.Id == id);
返回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存在;
}
}
}

p>

  public interface IIdentifyable:IIdentifyable< int> 
{
}

public interface IIdentifyable< out TId>
{
TId Id {get; }
}

看起来像这样的实体:

  public class CustomerEntity:IIdentifyable< int> 
{
public string Name {get;组; }
public int Id {get; set; }
}

public class ProductEntity:IIdentifyable< Guid>
{
public string Name {get;组; }
public Guid Id {get; set; }
}

我的问题是它不能编译。我得到这个错误:

我试图将它更改为 x => Equals(x.Id,id),但EF无法翻译它。任何方式吗?



我知道我可以使用 Find()而不是 FirstOrDefault 。但我比上面提到的方法更需要这个。 有什么方法可以让EF比较 TId TId <$ c $目前只有 guid int 。我已经看到了下面的问题,但他们没有处理有关转换为SQL的问题。





解决方案

这是一个泛型的已知问题,通常使用 EqualityComparer< T> .Default 来代替 == 运算符。然而,这种方法不适用于LINQ to Entities。



解决这个问题的一种方法是使用 Expression System.Linq.Expressions 命名空间中的类>:
$ b

  public class GenericRepository< TEntity,TId>其中TEntity:class,IIdentifyable< TId> 
{
protected static Expression< Func< TEntity,bool>> EqualsPredicate(TId id)
{
表达式< 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);


$ / code $ / pre

并像这样使用它:

  dbSet.FirstOrDefault(EqualsPredicate(id)); 

  dbSet.Any(EqualsPredicate(ID)); 

等。



更新:这是另一种适用于EF的方式。



将以下约束添加到 GenericRepository

 其中TId:IEquatable< TId> 

,然后使用等于方法

  x => x.Id.Equals(ID); 


I have this generic class, which uses 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 ;
        }
    }
}

And these interfaces:

public interface IIdentifyable : IIdentifyable<int>
{
}

public interface IIdentifyable<out TId>
{
    TId Id { get; }
}

And entities that looks like this:

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

My issue is that it doesn't compile. I get this error:

I tried to change it to x => Equals(x.Id, id), but then EF cannot translate it. Any way around it?

I know that I can use Find() instead of FirstOrDefault. But I need this for more than the methods mentioned above. Is there any way I can let EF compare TId with TId? TId is currently only guid and int. I've already seen the questions below, but they don't handle the issue regarding translation to SQL.

Can't operator == be applied to generic types in C#?

How to solve Operator '!=' cannot be applied to operands of type 'T' and 'T'

解决方案

This is a known issue with generics which normally is handled by using EqualityComparer<T>.Default instead of the == operator. However this approach doesn't work with LINQ to Entities.

One way to solve it is to build the predicate dynamically using the Expression class from the System.Linq.Expressions namespace like this:

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

and use it like this:

dbSet.FirstOrDefault(EqualsPredicate(id));

or

dbSet.Any(EqualsPredicate(id));

etc.

Update: Here is another way that works with EF.

Add the following constraint to the GenericRepository class

where TId : IEquatable<TId>

and then use Equals method

x => x.Id.Equals(id);

这篇关于EF - 不能将运算符'=='应用于'TId'和'TId'类型的操作数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-18 14:47