我正在尝试开发一些需要运行以下复杂查询的动态类型的代码。
tag_user
实际上我想找到包含其中一个 searchKeys 的行。例如,如果我有这样的搜索键:
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('label');
$table->timestamps();
});
Schema::create('tag_user', function (Blueprint $table) {
$table->unsignedBigInteger('tag_id');
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->primary(['tag_id','user_id']);
});
}
然后我想找到例如名称为 IEnumerable<string> searchKeys = search.KeySearch.Split(',').Select(key => key.Trim());
var searchedIds = _dbContext.Keys
.Where(key => searchKeys.Any(searchKey => EF.Functions.Like(key.Name, searchKey)))
或名称为 var searchKeys = ["name_%", "last_x%];
的行。
但是 ef cores 说它无法翻译,并建议要么编写可翻译的查询,要么在客户端执行查询(这在我的问题中不合适)。
System.InvalidOperationException: LINQ 表达式 'DbSet() .Where(k => __searchKeys_0 .Any(searchKey => __Functions_1 。像( 匹配表达式:k.Name, 模式:searchKey)))' 无法翻译。要么以可翻译的形式重写查询,要么切换到客户端 通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用来显式评估。有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2101038。
所以我想将查询更改为可翻译的查询,但我不知道是什么问题,也没有开始修复它的线索。
答案 0 :(得分:2)
因此以下解决方案至少应该有效:
var searchKeys = search.KeySearch.Split(',').Select(key => key.Trim());
var queries = new List<IQueryable<Key>>();
foreach (var searchKey in searchKeys)
{
queries.Add(_dbContext.Keys.Where(k => EF.Functions.Like(k.Name, searchKey)));
}
var finalQuery = queries[0];
for (var i = 1; i < queries.Count; i++)
{
finalQuery = finalQuery.Union(queries[i]);
}
var filteredKeys = finalQuery.ToList();
我认为代码效率很低,因为它会导致多个 UNION
语句。
一个更高效的选择是构建一个表达式树 Expression<Func<Key, bool>>
,它基本上产生以下结果:.Where(k => EF.Functions.Like(k.Name, searchKey[0]) || ... || EF.Functions.Like(k.Name, searchKey[5]))
。