Lix*_*ixi 4 generics comparison types entity-framework
我有以下问题:我有一个使用为Int或Guid实体键设计的DbContext的通用EF存储库,所以我有一个基本实体类:
public class EntityBase<TKey> where TKey : struct, IComparable
{
public virtual TKey Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
当我运行代码
public virtual void LoadEntity()
{
TEntity entity = Repository.Get<TEntity, TKey>(e => object.Equals(e.Id, EntityId));
}
Run Code Online (Sandbox Code Playgroud)
要么
public virtual void LoadEntity()
{
TEntity entity = Repository.Get<TEntity, TKey>(e => e.Id.CompareTo(EntityId) == 0);
}
Run Code Online (Sandbox Code Playgroud)
其中Entity的类型为TKey,并在派生类中设置为int,例如,我收到以下错误:
无法将类型"System.Int32"强制转换为"System.Object"类型.LINQ to Entities仅支持转换实体数据模型基元类型.
Repository.Get只是传递谓词参数作为对DbSet存储库的Where调用的过滤器;
我理解错误 - EF尝试转换为SQL语句,并且不知道如何处理对象比较.但我不知道如何重写基类和/或LoadEntity()函数以允许EF使用基本类型进行操作.有任何想法吗?
Paw*_*wel 11
我认为有一个简单的方法,但它是一个黑客.让我再次强调它 - 它真的是一个黑客.你可以试试这个:
Repository.Get<TEntity, TKey>(e => (object)e.Id == (object)EntityId);
Run Code Online (Sandbox Code Playgroud)
一般来说,上面的代码不起作用.在CLR世界中,值将被加框并将通过引用进行比较.即使盒装值相同,引用也会不同,因此结果将是错误的.但是,CLR不会执行EF查询,而是将其转换为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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在Filter方法中,我构建了一个可以组成的过滤器表达式.在这个例子中,有效查询看起来像这个DbSet().其中(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; }
}
Run Code Online (Sandbox Code Playgroud)
您可以像这样调用GetEntity方法: var e2 = GetEntity(e => e.Id, guidKey);
归档时间: |
|
查看次数: |
2288 次 |
最近记录: |