是否可以使用IComparable在Entity Framework中比较实体? [英] Is it possible to use IComparable to compare entities in Entity Framework?

查看:48
本文介绍了是否可以使用IComparable在Entity Framework中比较实体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实现 IComparable 的POCO类.

I have a POCO class that implements IComparable.

public interface IEntity : IComparable
{
    long Id { get; set; }

    Func<IEntity, bool> CompareFunction { get; }
}

public abstract class BaseEntity : IEntity
{
    public virtual long Id { get; set; }

    public Func<IEntity, bool> CompareFunction
    {
        get
        {
            Func<IEntity, bool> compare = EvaluateEquivalency;
            return compare;
        }
    }

    public static int Compare(BaseEntity left, BaseEntity right)
    {
        if (object.ReferenceEquals(left, right))
        {
            return 0;
        }

        if (object.ReferenceEquals(left, null))
        {
            return -1;
        }

        return left.CompareTo(right);
    }

    public static bool operator ==(BaseEntity left, BaseEntity right)
    {
        if (object.ReferenceEquals(left, null))
        {
            return object.ReferenceEquals(right, null);
        }

        return left.Equals(right);
    }

    public static bool operator !=(BaseEntity left, BaseEntity right)
    {
        return !(left == right);
    }

    public static bool operator <(BaseEntity left, BaseEntity right)
    {
        return Compare(left, right) < 0;
    }

    public static bool operator >(BaseEntity left, BaseEntity right)
    {
        return Compare(left, right) > 0;
    }

    public override bool Equals(object obj)
    {
        IEntity other;

        if (!(obj is IEntity)) return false;

        other = (IEntity)obj;

        if (object.ReferenceEquals(other, null))
        {
            return false;
        }

        return this.CompareTo(other) == 0;
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public virtual int CompareTo(object obj)
    {
        if (obj == null) throw new ArgumentNullException("obj");
        if (!(obj is IEntity)) throw new ArgumentException("obj is not an IEntity");

        if (this.Id == ((IEntity)obj).Id) return 0;

        return -1;
    }

    private bool EvaluateEquivalency(IEntity toCompare)
    {
        return Equals(toCompare);
    }
}

我的 DbContext 中的POCO类有 DbSet .

There is DbSet for my POCO class in my DbContext.

但是,当我执行 BaseRepository.Exists()时,我得到的是 System.NotSupportedException .

However, when I execute BaseRepository.Exists() I get a System.NotSupportedException.

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
    ...

    private TEntity Exists(TEntity entity)
    {
        return Context.DbSet<TEntity>.FirstOrDefult(i => i.CompareTo(entity) == 0);
    }

    private TEntity ExistsV2(TEntity entity)
    {
        return Context.DbSet<TEntity>.FirstOrDefult(i => i.CompareFunction(entity) == 0);
    }

    ...
}

异常堆栈跟踪看起来像...

The exception stack trace looks like...

System.NotSupportedException was unhandled by user code
  Message=Unable to create a constant value of type '{My POCO Class}'. Only primitive types or enumeration types are supported in this context.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.EqualsTranslator.TypedTranslate(ExpressionConverter parent, BinaryExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FirstPredicateTranslatorBase.Translate(ExpressionConverter parent, MethodCallExpression call)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.Convert()
       at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
       at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
       at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence)
       at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
       at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
       at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
       at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)

当我执行 BaseRepository.ExistsV2()时,我会得到略有不同的 System.NotSupportedException .

When I execute BaseRepository.ExistsV2() I get a slightly different System.NotSupportedException.

System.NotSupportedException was unhandled by user code
  HResult=-2146233067
  Message=The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.ELinq.ExpressionConverter.NotSupportedTranslator.Translate(ExpressionConverter parent, Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FirstPredicateTranslatorBase.Translate(ExpressionConverter parent, MethodCallExpression call)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
       at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
       at System.Data.Objects.ELinq.ExpressionConverter.Convert()
       at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
       at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
       at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
       at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence)
       at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
       at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
       at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
       at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)

我已经读过实体框架不支持 IComparable 吗?无论如何还是有人知道该功能是否可以在EF6中使用?

I've read the Entity Framework doesn't support IComparable? Is there anyway around this or does anyone know whether the functionality will be available in EF6?

推荐答案

不,您不能这样做.

EF要求所有操作都能够执行100%服务器端.要支持 IComparable IEquatable ,将要求EF能够将任意IL转换为SQL,但这尚无法做到.

EF requires all operations to be able to execute 100% server-side. Supporting IComparable or IEquatable would require EF to be able to translate arbitrary IL into SQL, which it can't yet do.

否则,它必须将整个未过滤的结果集传递给客户端.您可以通过使用 AsEnumerable():

Otherwise, it would have to pass the entire unfiltered result set to the client. You can achieve exactly this by using AsEnumerable():

Context.DbSet<TEntity>.AsEnumerable().FirstOrDefault(i => i.CompareTo(entity) == 0);

这当然会运行得很慢,因此,如果表的大小很大,我不建议这样做.

This will of course run quite slow though, so I wouldn't recommend it if the table is of any significant size.

这篇关于是否可以使用IComparable在Entity Framework中比较实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆