是否投射导致 IQueryable 在 Linq-to-SQL 中进行评估?其使用有哪些限制?

发布于 2024-10-19 14:53:58 字数 359 浏览 4 评论 0原文

Cast 是否会导致 IQueryable 在 Linq-to-SQL 中进行计算?

其使用有哪些限制?

看起来如果我为记录创建显式转换为域对象,例如:

  IQueryable<TSqlRecord> q;
  var cast = q.Cast<TDomainObject>();

那么我应该收到错误,因为 Linq-to-Sql 显然无法处理域对象构造函数。

但是,我可以将 IQueryable 转换为其接口 IHasIntId 而不强制查询进行评估吗?

Does Cast cause an IQueryable to evaluate in Linq-to-SQL?

What are the restrictions on its use?

It seems like if I created an explicit conversion for a record to a domain object like:

  IQueryable<TSqlRecord> q;
  var cast = q.Cast<TDomainObject>();

Then I should get an error, because Linq-to-Sql and obviously can't process the domain object constructor.

But, can I cast IQueryable<TSqlRecord> to its interface IHasIntId without forcing the query to evaluate?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹊巢 2024-10-26 14:53:58

强制转换是延迟的,不会立即执行。这是因为它(本身)没有枚举源。仅当枚举某些内容时,才会运行查询。

向上转型是没有问题的。查询将正常工作。

回想一下 - 查询适用于数据库行而不是实例。仅当行到达本地时才会创建实例。对cast 的调用所做的只是更改结果中使用的引用类型 - 它不会更改新实例的类型。

class SpecificObject : DomainObject

MyDataContext myDC = new MyDataContext();
IQueryable<DomainObject> query = myDC.SpecificObjects.Cast<DomainObject>();

Console.WriteLine(myDC.GetCommand(query).CommandText);

但是 - 这并不是真正有用 - 因为行上的属性位于原始类型上,现在您无法在查询的其余部分引用这些属性。


贬低其实并没有多大作用。 LinqToSql 假定每行都是 Table 中的 T 类型。不是什么TChild。这将生成一个查询,为表中的每一行选择 null。

class SpecificObject : DomainObject

MyDataContext myDC = new MyDataContext();
IQueryable<SpecificObject> query = myDC.DomainObjects.Cast<SpecificObject>();

Console.WriteLine(myDC.GetCommand(query).CommandText);

隐式转换……对此应该非常小心。即使 LinqToObject 的 Enumerable.Cast 也不尊重隐式转换操作(请参阅 此处此处)。当然,这与 LinqToSql 没有任何关系 - 但原则很重要 - .net 转换与 c# 隐式转换和任何 sql 事物不同。您必须记住您正在编写的代码的执行环境。

Cast is deferred and does not cause immediate execution. This is because it does not (itself) enumerate the source. Only when something is enumerated, is the query run.

Upcasting is no problem. The query will work fine.

Recall - the query works on database rows and not on instances. Instances are only created when the rows arrive locally. All that this call to cast does is to change the reference type used in the result - it doesn't change the type of instance new'd up.

class SpecificObject : DomainObject

MyDataContext myDC = new MyDataContext();
IQueryable<DomainObject> query = myDC.SpecificObjects.Cast<DomainObject>();

Console.WriteLine(myDC.GetCommand(query).CommandText);

But - that's not really useful - as the properties on the row were on the original type and now you can't refer to those properties in the rest of the query.


Downcasting doesn't really do much. LinqToSql presumes that the each row is of type T from the Table<T>. Not some TChild. This will generate a query selecting null for each row from the table.

class SpecificObject : DomainObject

MyDataContext myDC = new MyDataContext();
IQueryable<SpecificObject> query = myDC.DomainObjects.Cast<SpecificObject>();

Console.WriteLine(myDC.GetCommand(query).CommandText);

Implicit conversion... one should be very careful with that. Even LinqToObject's Enumerable.Cast<T> doesn't respect implicit conversion operations (see here and here). Of course, that doesn't have anything to do with LinqToSql - but the principle matters - .net casting is not the same as c# implicit conversion and whatever sql thing. You must bear in mind the execution environment of the code you're writing.

我ぃ本無心為│何有愛 2024-10-26 14:53:58

不可以,您无法将 IQueryable 转换为 IHasIntId,因为 IQueryable 表示 TSqlRecord< 类型的多个对象/code>,而IHasIntId仅代表一个对象。至少,这就是我对你的样本的理解。
我认为,你的问题应该这样问:

我可以将 IQueryable 转换为 IQueryable

这个问题的答案是:不,这是不可能的
MSDN 声明如下:

Cast(IQueryable) 方法生成一个 MethodCallExpression,该表达式表示将调用 Cast(IQueryable) 本身作为构造的泛型方法。然后,它将 MethodCallExpression 传递给由源参数的 Provider 属性表示的 IQueryProvider 的 CreateQuery(Expression) 方法。

由于执行表示调用 Cast(IQueryable) 的表达式树而发生的查询行为取决于源参数类型的实现。预期的行为是将源中的值转换为 TResult 类型。

这意味着,对 Cast 的调用并未真正执行,而是由查询提供程序解释,例如转换为 SQL。

No, you can't cast IQueryable<TSqlRecord> to IHasIntId, because IQueryable<TSqlRecord> represents multiple objects of type TSqlRecord, whereas IHasIntId only represents one object. At least, that's how I understand your sample.
I think, your question should have been asked like this:

Can I cast IQueryable<TSqlRecord> to IQueryable<IHasIntId>.

The answer to that question is: No, it's not possible
MSDN states the following:

The Cast(IQueryable) method generates a MethodCallExpression that represents calling Cast(IQueryable) itself as a constructed generic method. It then passes the MethodCallExpression to the CreateQuery(Expression) method of the IQueryProvider represented by the Provider property of the source parameter.

The query behavior that occurs as a result of executing an expression tree that represents calling Cast(IQueryable) depends on the implementation of the type of the source parameter. The expected behavior is that it converts the values in source to type TResult.

This means, that the call to Cast is not really executed, but interpreted by the query provider and for example translated into SQL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文