gpt4 book ai didi

entity-framework - EF 对象与泛型类型的比较

转载 作者:行者123 更新时间:2023-12-04 22:34:36 27 4
gpt4 key购买 nike

我有以下问题:我有一个通用的 EF 存储库,它使用为 Int 或 Guid 实体键设计的 DbContext,所以我有一个基本实体类:

public class EntityBase<TKey> where TKey : struct, IComparable
{
public virtual TKey Id { get; set; }
}
  • TKey 将在派生类中作为 Int 或 Guid 提供。

  • 当我运行代码时
    public virtual void LoadEntity()
    {
    TEntity entity = Repository.Get<TEntity, TKey>(e => object.Equals(e.Id, EntityId));
    }

    或者
    public virtual void LoadEntity()
    {
    TEntity entity = Repository.Get<TEntity, TKey>(e => e.Id.CompareTo(EntityId) == 0);
    }

    其中 Entity 的类型为 TKey 并且在派生类中设置为 int,例如,我收到以下错误:

    无法将“System.Int32”类型转换为“System.Object”类型。 LINQ to Entities 仅支持强制转换实体数据模型基元类型。

    Repository.Get 只需传递谓词参数作为 DbSet 存储库的 Where 调用的过滤器;

    我理解错误 - EF 尝试转换为 SQL 语句,但不知道如何处理对象比较。但我不知道如何重写基类和/或 LoadEntity() 函数以允许 EF 使用原始类型进行操作。
    有任何想法吗?

    最佳答案

    我认为有一个简单的方法可以解决它,但它是 hack 。让我再次强调 - 这真的是一个 hack 。你可以试试这个:

    Repository.Get<TEntity, TKey>(e => (object)e.Id == (object)EntityId);

    上面的代码一般不应该工作。在 CLR 世界中,这些值将被装箱并通过引用进行比较。即使装箱值相同,引用也会不同,因此结果将为假。但是,EF 查询不是由 CLR 执行而是转换为 SQL。因此,查询将被转换为类似的内容: WHERE Id = {EntityId},这正是您所需要的。同样,使用它需要了解这些东西如何以及为什么起作用,并且可能有点冒险。但是,由于存在黑客攻击,因此应该有一个更清洁的解决方案。事实上,干净的(这里不是简单的解决方案)是手动构建上述表达式。这是一个示例(抱歉,我没有完全使用您的实体):
        private static TEntity GetEntity<TEntity, TKey>(Expression<Func<TEntity, TKey>> property, TKey keyValue)
    where TKey : struct
    where TEntity : BaseEntity<TKey>
    {
    using (var ctx = new Context2())
    {
    var query = Filter(ctx.Set<TEntity>(), property, keyValue);
    return query.First();
    }
    }


    private static IQueryable<TEntity> Filter<TEntity, TProperty>(IQueryable<TEntity> dbSet,
    Expression<Func<TEntity, TProperty>> property,
    TProperty value)
    where TProperty : struct
    {

    var memberExpression = property.Body as MemberExpression;
    if (memberExpression == null || !(memberExpression.Member is PropertyInfo))
    {
    throw new ArgumentException("Property expected", "property");
    }

    Expression left = property.Body;
    Expression right = Expression.Constant(value, typeof (TProperty));

    Expression searchExpression = Expression.Equal(left, right);
    var lambda = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(left, right),
    new ParameterExpression[] {property.Parameters.Single()});

    return dbSet.Where(lambda);
    }

    请注意,在 Filter 方法中,我构建了一个可以组合的过滤器表达式。在这个例子中,有效查询看起来像这样 DbSet().Where(e => e.Id == idValue).First() (看起来类似于上面的 hack)但是你可以在这个查询之上使用其他 linq 运算符(包括对 Filter 方法的结果调用 Filter 方法以按多个条件过滤)

    我将实体和上下文定义如下:
    public class BaseEntity<TKey> where TKey : struct
    {
    public TKey Id { get; set; }
    }

    public class EntityWithIntKey : BaseEntity<int>
    {
    public string Name { get; set; }
    }

    public class EntityWithGuidKey : BaseEntity<Guid>
    {
    public string Name { get; set; }
    }

    public class Context2 : DbContext
    {
    public DbSet<EntityWithIntKey> EntitiesWithIntKey { get; set; }

    public DbSet<EntityWithGuidKey> EntitiesWithGuidKey { get; set; }
    }

    您可以像这样调用 GetEntity 方法: var e2 = GetEntity(e => e.Id, guidKey);

    关于entity-framework - EF 对象与泛型类型的比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10402029/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com