泛型 Linq 查询,用于获取具有指定键的实体数组
本文关键字:数组 实体 查询 Linq 用于 获取 泛型 | 更新日期: 2023-09-27 18:30:33
我需要对这样的东西进行通用查询,但在 Web 中找不到任何内容(可能是因为搜索不好!
int[] ids = new int[]{1,2,3}
var q = context.where(o=> ids.contains(o.id));
其中我的实体类型未知,但我确定:
- 主键为单个
- 主键类型为
int
- 我无法更改实体定义
所以签名是这样的:
Public IQueryable<T> GetRecords(int[] keys)
{
var dbset = context.Set<T>();
...//the generic query
}
同样重要的是,在泛型和非泛型实现中具有相同的 SQL 输出(具有相同的性能)。
private IDictionary<Type, string> _primaryKeyCache = new Dictionary<Type, string>();
public IQueryable<T> GetRecords(int[] keys)
{
var dbSet = context.Set<T>();
var type = typeof(T);
string primaryKeyName;
if(!_primaryKeyCache.TryGetValue(type, out primaryKeyName)){
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var set = objectContext.CreateObjectSet<YourEntity>();
var keyName = set.EntitySet.ElementType
.KeyMembers
.Select(k => k.Name)
.First();
_primaryKeyCache[type] = primaryKeyName = keyName;
}
return dbSet.DynamicContains<T, int>(primaryKeyName, keys);
}
private static IQueryable<T> DynamicContains<T, TProperty>(
this IQueryable<T> query,
string property,
IEnumerable<TProperty> items)
{
var pe = Expression.Parameter(typeof(T));
var me = Expression.Property(pe, property);
var ce = Expression.Constant(items);
var call = Expression.Call(typeof(Enumerable), "Contains", new[] { me.Type }, ce, me);
var lambda = Expression.Lambda<Func<T, bool>>(call, pe);
return query.Where(lambda);
}
这应该可以满足您的需求。
您可以使用多态性解决问题。Crete 一个接口,该接口声明整数Id
属性并在实体中实现,因为它对所有实体都是通用的。然后对泛型参数T
进行约束,强制它成为实现接口的类型,以便编译器知道T
将是具有Id
属性的类型,并且您将能够访问它:
// IId is the interface that should be implemented
public IQueryable<T> GetRecords<T>(int[] keys) where T : IId
{
var dbset = context.Set<T>();
...//the generic query
}
创建一个新接口,例如 IKeyedByIntEntity
public interface IKeyedByIntEntity
{
int Key { get; }
}
让要在查询中使用的所有实体实现接口。在理想情况下,字段具有相同的名称,因此您可以将其用作接口中的属性名称,因此不必更改实体的实现。
public class MyEntity : IKeyedByIntEntity
{
public int Key { get; set; }
public string Value { get; set; }
}
更新您的 GetRecords 函数或类以需要接口,类似于以下接口之一......
public class Fetch
{
public IQueryable<T> GetRecords<T>(int[] keys)
where T : IKeyedByIntEntity
{
IQueryable<T> records = this.context.Where(e => keys.Contains(e.Key));
return records;
}
}
public class Fetch<T> where T : IKeyedByIntEntity
{
public IQueryable<T> GetRecords(int[] keys)
{
IQueryable<T> records = this.context.Where(e => keys.Contains(e.Key));
return records;
}
}