我有以下通用方法,我需要能够执行LINQ Where查询:
public static List<T> GetItems<T>(Guid parentId = new Guid()) where T : new()
{
var db = new SQLiteConnection(_dbPath);
List<T> result;
if (parentId != Guid.Empty)
{
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
}
else
{
result = db.Table<T>().ToList();
}
db.Close();
return result;
}
编译器不喜欢以下行
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
错误:无法解析'ParentId'
是否可以在LINQ查询中以这种方式使用泛型?请注意,类型为T的对象将始终具有ParentId属性。
答案 0 :(得分:5)
您应该将T
参数与某些包含所需值的接口相结合。此外,您应该将此接口添加到包含此类的字段或基类型的所有类型。
public interface IHierarchy
{
public Guid ParentId { get; }
}
public static List<T> GetItems<T>(Guid parentId = new Guid())
where T : IHierarchy, new()
{
var db = new SQLiteConnection(_dbPath);
List<T> result;
if (parentId != Guid.Empty)
{
result = db.Table<T>().Where(i => i.ParentId.Equals(parentId)).ToList();
}
else
{
result = db.Table<T>().ToList();
}
db.Close();
return result;
}
如果您有两种类型的实体,第一种包含所需的值而第二种不包含,则此方案可能会有两次重载。
答案 1 :(得分:2)
您使用的是通用类型,编译器不知道您将使用哪个entity
。
只需使用reflection
语言的.NET
功能。
result = db.Table<T>().Where(i => i.GetType().GetProperty("ParentId").GetValue(src, null).Equals(parentId)).ToList();
答案 2 :(得分:1)
问题在于,在您的代码中,您假设每个T
都有一个GUID属性ParentId
,而实际上您只需要每个T都有一个默认构造函数。您需要要求每个T都有一个ParentId。
你可以通过要求每个T实现一些接口来做到这一点。和其他答案一样,但是这非常麻烦,因为对于你想要使用这个函数的每个类,你需要实现这个接口。
函数Enumerable.Where
似乎能够完成相同的工作,而不需要输入项的任何接口。所以让我们使用相同的方法:
作为输入,我们告诉使用哪个属性(在您的情况下为ParentId)以及要比较的值(在您的情况下为parentId)。
我们唯一的要求是我们必须能够将ParentId与parentId进行比较:它应该是IEquatable
public List<T> GetItems<T, TKey>(Func<T, TKey> keySelector, Tkey value)
TKey : IEquatable<TKey>,
{
...
result = db.Table<T>()
.Where(t => keySelector(t).Equals(value))
.ToList();
}
用法:
Guid value = ...
var items = GetItems<MyClass, Guid>(item => item.ParentId, value);
此功能也适用于其他类和其他属性:
int studentId = ...
var students = GetItems<Student, int>(student => student.Id, studentId);
var otherStudents = GetItems<Student, string>(student => student.Name, "John");
两面评论:
- 您使用new Guid()
定义一些默认Guid
。使用Guid.Empty
速度更快
- 您不会创建类型为T的新项。它们已经在您的dbContext.Table中。因此,您不需要new()。
- 但是,如果你的表要求T是一个类,那么你应该要求它。请参阅表定义:
where T : class