LINQ TO SQL 替换方法
LINQ TO SQL Replace method
我有代码,它工作正常。
using (var dbContext = new UnitOfWorkFactory(sqlConnection).Create())
{
var result = dbContext.Repository<SomeTable>()
.Get()
.AsNoTracking()
.Where(r => r.Id == 1)
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = item.TableName.Replace("$", "_")
})
.SingleOrDefault();
当我尝试在单独的私有方法中替换逻辑时出现异常。我知道主要原因是 LINQ to SQL 提供程序无法将 clr 方法转换为 SQL。
...
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace(item.TableName)
})
...
其实我想我必须使用表达式树,但无法解决我必须如何编写它。当我从 SubQueryReplace 方法尝试 return Expression<Func<string>>
时,CLR 编译器不高兴,但是当我尝试做类似
的事情时
private Expression<Func<string, string>>SubQueryReplace(string fieldValue)
{
Expression<Func<string, string>> exp = (tableName) => tableName.Replace("D", "_");`
return exp
}
...
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace.Compile.Invoke(item.TableName)
})
...
LINQ to Sql 不明白我想从中得到什么。
如您所见,我很困惑。请帮助解决这个语法任务。
我说得对吗,您的问题是 IQueryable 不能使用任何本地函数,也不能将所有标准 LINQ 方法转换为 SQL,如 supported and unsupported LINQ methods 中所述?
我会选择 AsEnumerable。 AsEnumerable 会将输入带到本地内存,以便您可以调用所需的任何本地函数。
由于您的查询结果似乎只是一个元素,因此如果在将其转换为 OriginalTableName 之前将完整的 tableName 传输到本地内存就没有问题
var result = dbContext.Repository<SomeTable>()
...
.Where(someTableElement => someTableElement.Id == 1)
.Select(tableItem => new
{
TableId = tableItem.TableId,
TableName = tableIem.TableName,
})
.AsEnumerable()
// from here, all elements (expected to be only one) are in local memory
// so you can call:
.Select(localItem => new
{
TableId = localItem.TableId,
OriginalTableName = localItem.TableName.Replace("$", "_")
})
.SingleOrDefault();
使用AsEnumerable时要小心。尽量不要将大量数据传输到您不会使用的本地内存。所以尽量在 AsQueryable 的时候执行 Join / Where / Select 。仅当您将数据限制在您真正计划使用的范围内时,才将其移动到本地内存
使用LinqKit,写:
...
.AsExpandable()
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace(item.TableName).Expand()
})
...
我有代码,它工作正常。
using (var dbContext = new UnitOfWorkFactory(sqlConnection).Create())
{
var result = dbContext.Repository<SomeTable>()
.Get()
.AsNoTracking()
.Where(r => r.Id == 1)
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = item.TableName.Replace("$", "_")
})
.SingleOrDefault();
当我尝试在单独的私有方法中替换逻辑时出现异常。我知道主要原因是 LINQ to SQL 提供程序无法将 clr 方法转换为 SQL。
...
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace(item.TableName)
})
...
其实我想我必须使用表达式树,但无法解决我必须如何编写它。当我从 SubQueryReplace 方法尝试 return Expression<Func<string>>
时,CLR 编译器不高兴,但是当我尝试做类似
private Expression<Func<string, string>>SubQueryReplace(string fieldValue)
{
Expression<Func<string, string>> exp = (tableName) => tableName.Replace("D", "_");`
return exp
}
...
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace.Compile.Invoke(item.TableName)
})
...
LINQ to Sql 不明白我想从中得到什么。
如您所见,我很困惑。请帮助解决这个语法任务。
我说得对吗,您的问题是 IQueryable 不能使用任何本地函数,也不能将所有标准 LINQ 方法转换为 SQL,如 supported and unsupported LINQ methods 中所述?
我会选择 AsEnumerable。 AsEnumerable 会将输入带到本地内存,以便您可以调用所需的任何本地函数。
由于您的查询结果似乎只是一个元素,因此如果在将其转换为 OriginalTableName 之前将完整的 tableName 传输到本地内存就没有问题
var result = dbContext.Repository<SomeTable>()
...
.Where(someTableElement => someTableElement.Id == 1)
.Select(tableItem => new
{
TableId = tableItem.TableId,
TableName = tableIem.TableName,
})
.AsEnumerable()
// from here, all elements (expected to be only one) are in local memory
// so you can call:
.Select(localItem => new
{
TableId = localItem.TableId,
OriginalTableName = localItem.TableName.Replace("$", "_")
})
.SingleOrDefault();
使用AsEnumerable时要小心。尽量不要将大量数据传输到您不会使用的本地内存。所以尽量在 AsQueryable 的时候执行 Join / Where / Select 。仅当您将数据限制在您真正计划使用的范围内时,才将其移动到本地内存
使用LinqKit,写:
...
.AsExpandable()
.Select(item => new
{
TableId = item.TableId,
OriginalTableName = SubQueryReplace(item.TableName).Expand()
})
...