- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在为 JSON.NET 创建一个 JsonConverter,它能够序列化和反序列化表达式 (System.Linq.Expressions)。我只完成了最后 5% 左右的工作,而且我无法运行从反序列化表达式生成的 LINQ-to-SQL 查询。
表达式如下:
Expression<Func<TestQuerySource, Bundle>> expression = db => (
from b in db.Bundles
join bi in db.BundleItems on b.ID equals bi.BundleID
join p in db.Products on bi.ProductID equals p.ID
group p by b).First().Key;
这是 LINQ-to-SQL 中非常简单的分组查询。 TestQuerySource
是 System.Data.Linq.DataContext
的实现. Bundle
, BundleItem
, Product
, 都是用 TableAttribute
修饰的 LINQ-to-SQL 实体和其他其他映射属性。它们对应的datacontext属性都是Table<T>
属性正常。换句话说,这里没有什么特别值得注意的。
但是,当我尝试在反序列化表达式后运行查询时,出现以下错误:
System.Reflection.TargetInvocationException:
Exception has been thrown by the target of an invocation. --->
System.NotSupportedException: The member '<>f__AnonymousType0`2[Bundle,BundleItem].bi' has no supported translation to SQL.
我知道这意味着表达式正在做的事情不能被 LINQ-to-SQL 查询提供程序转换为 SQL。它似乎与创建匿名类型作为查询的一部分有关,就像作为连接语句的一部分一样。通过比较原始表达式和反序列化表达式的字符串表示来支持此假设:
原始(工作):
{db => db.Bundles
.Join(db.BundleItems,
b => b.ID,
bi => bi.BundleID,
(b, bi) => new <>f__AnonymousType0`2(b = b, bi = bi))
.Join(db.Products,
<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.bi.ProductID,
p => p.ID,
(<>h__TransparentIdentifier0, p) =>
new <>f__AnonymousType1`2(<>h__TransparentIdentifier0 = <>h__TransparentIdentifier0, p = p))
.GroupBy(<>h__TransparentIdentifier1 =>
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.b,
<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.p)
.First().Key}
反序列化(损坏):
{db => db.Bundles
.Join(db.BundleItems,
b => b.ID,
bi => bi.BundleID,
(b, bi) => new <>f__AnonymousType0`2(b, bi))
.Join(db.Products,
<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.bi.ProductID,
p => p.ID,
(<>h__TransparentIdentifier0, p) => new <>f__AnonymousType1`2(<>h__TransparentIdentifier0, p))
.GroupBy(<>h__TransparentIdentifier1 =>
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.b,
<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.p)
.First().Key}
当需要访问匿名类型的非基本类型属性时,问题似乎会发生。在这种情况下 bi
正在访问属性以到达 BundleItem
的 ProductID
属性(property)。
我想不通的是区别是什么——为什么在原始表达式中访问该属性可以正常工作,但在反序列化表达式中却不行。
我猜这个问题与序列化过程中丢失的匿名类型的某种信息有关,但我不确定去哪里找它,甚至不知道要找什么。
其他示例:
值得注意的是,像这样更简单的表达式效果很好:
Expression<Func<TestQuerySource, Category>> expression = db => db.Categories.First();
即使进行分组(不加入)也可以:
Expression<Func<TestQuerySource, Int32>> expression = db => db.Categories.GroupBy(c => c.ID).First().Key;
简单的连接工作:
Expression<Func<TestQuerySource, Product>> expression = db => (
from bi in db.BundleItems
join p in db.Products on bi.ProductID equals p.ID
select p).First();
选择匿名类型有效:
Expression<Func<TestQuerySource, dynamic>> expression = db => (
from bi in db.BundleItems
join p in db.Products on bi.ProductID equals p.ID
select new { a = bi, b = p }).First();
这里是最后一个例子的字符串表示:
原文:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(a = bi, b = p))
.First()}
反序列化:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(bi, p))
.First()}
最佳答案
我认为不同之处在于,在工作示例中,匿名类型是使用属性构造的,而在损坏的情况下,它是使用构造函数实例化的。
L2S 假设在查询翻译期间,如果您为属性分配特定值,该属性将只返回该值。
L2S 不假定名称为 abc 的构造函数参数将初始化名为 Abc 的属性。这里的想法是,一个 ctor 可以做任何事情,而一个属性只会存储一个值。
请记住,匿名类型与自定义 DTO 类没有什么不同(字面意思!L2S 无法区分它们)。
在您的示例中,您要么 a) 不使用匿名类型(有效) b) 仅在最终投影中使用 ctor(有效 - 一切都作为最终投影工作,甚至是任意方法调用。L2S 很棒。)或c) 在查询的 sql 部分使用构造函数(损坏)。这证实了我的理论。
试试这个:
var query1 = someTable.Select(x => new CustomDTO(x.SomeString)).Where(x => x.SomeString != null).ToList();
var query2 = someTable.Select(x => new CustomDTO() { SomeString = x.SomeString }).Where(x => x.SomeString != null).ToList();
第二个可以,第一个不行。
(大牛更新)
重建反序列化表达式时,确保使用正确的重载 Expression.New
如果需要通过构造函数设置属性。正确使用的重载是 Expression.New(ConstructorInfo, IEnumerable<Expression>, IEnumerable<MemberInfo>)
或 Expression.New(ConstructorInfo, IEnumerable<Expression>, MemberInfo[])
.如果使用其他重载之一,参数将只传递到构造函数,而不是分配给属性。
关于c# - "No supported translation to SQL"反序列化 IQueryable 表达式后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10035633/
var page = pagesRepository.GetPages(); var categoryPages = page.ChildCategoryPages; var articlePages
是否可以将 IQueryable 对象转换为 IQueryable,其中 T 是映射实体? (T 将是 POCO 类)。 提前致谢。 最佳答案 就 Cast() 它。假设它是相同类型的可查询。否则你可
我只是想知道为什么会有一个 IQueryable没有通用功能的版本? 最佳答案 The generic IQueryable is the one you use most often in meth
我有一个 IQueryable它是根据一些输入参数(排序和过滤器)创建的。 可以应用这个 IQueryable到 DbSet我有DbContext ? 例如: // create the query
我们正在尝试转换 IQueryable 的实例到 IQueryable , SpecificEntityObject类型仅在运行时已知。 我们已尝试使用下面的代码,该代码无法编译,因为类型或命名空间
最近几天我在互联网上搜索了解决方案,但没有找到我想要的。基本上,这是我的问题: 我有一个需要实现的接口(interface),它有一个返回 IQueryable 的方法(我无权访问该接口(interf
与IEnumerable相同对比IEnumerable .这是疏忽吗?或者当您没有指定类型来实现像 .Count() 这样的扩展时,是否存在问题? , .Where()等不可能? 最佳答案 来自doc
这是 Automapper 专业人员的问题。我已经尝试做查询映射好几天了——但没有成功。似乎 Automapper 不打算按照我想要的方式使用它。但也许我错了。那么问题来了…… 我有这样的类(clas
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭去年。 Improve th
我有一个类Something实现 ISomething .如何从 IQueryable 转换/转换到 IQueryable .当我尝试转换时,我能够编译,但转换的结果始终为 NULL。 背景:我这样做
我了解协方差,并且我知道一般来说在 v4.0 之前它在 C# 中是不可能的。 但是我想知道一个具体案例。有什么方法可以进行转换IQueryable至IQueryable通过以某种方式创建一个包装类,该
如果IQueryable接口(interface)在服务器中执行查询表达式,而不是像 IEnumerable 那样获取所有记录,为什么是IQueryable未被 IEnumerable 取代哪里可以更
这个问题在这里已经有了答案: Why covariance and contravariance do not support value type (4 个答案) 关闭 7 年前。 为什么编译器不
我想做这样的事情 public IQueryable GetPaged(IQueryable query, int startIndex, int pageSize) {
我正在开发一个使用新 Web API 的项目,我注意到有人从 Get 方法返回了一个 IQueryable。 我的理解是 IQueryable 可用于提高性能(延迟执行),但我认为 HTTP 连接另一
我正在重构我的 EF 存储库类以使其可测试,遵循这篇优秀博客文章中的建议: https://blog.iannelson.uk/testing-linq-queries/ 一切都很好,我也能够像在博客
我有一个包含 IQueryable 的通用函数其中每一行都包含一个具有一组属性的类的实例。 我有另一个类 (MyClass),它具有与上面的类 T 相同的一些属性...即相同的名称和数据类型。 我还有
我正在尝试使用 Automapper 将 IQueryable 映射到 IQueryable 以生成 Linq。我正在开发一个带有 Entity Framework 和 oracle 11g 的 We
我有一个对象是: IQueryable 我想将它传递给一个函数,该函数需要: IQueryable Foo 确实实现了 IFoo 为什么不能编译?什么是最好的转换方式来让这项工作发挥作用? 最佳答案
我有一个查询可以获取一些过滤后的数据,但它给了我一些奇怪的结果。使用 VS Code 调试器查看附件图像(var source 是一个 Queryable,类似于 _dbContext.ModelNa
我是一名优秀的程序员,十分优秀!