gpt4 book ai didi

entity-framework - 在 LINQ to SQL 查询中使用了 'new' 运算符,但在每个结果中都引用了相同的实例

转载 作者:行者123 更新时间:2023-12-02 04:02:25 24 4
gpt4 key购买 nike

谁能解释我在下面的最小代码示例中看到的行为?似乎对于给定的字段或属性,Entry 的两个实例相同。类在 LINQ to SQL 查询的每次迭代中都被重用,即使我使用 new运算符(operator)。 LINQ to objects 查询不会出现同样的问题。我使用 .NET Framework 4 创建了一个 C# 控制台应用程序项目并连接到 SQL Server 2005 Enterprise 数据库。

public class Set
{
public Entry Field;
public Entry Property { get; set; }
}

public class Entry
{
public int ID;
public string Name { get; set; }
}

class Program
{
static void Main(string[] args)
{
var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database
var resultQuery = (
from x in dc.SomeTable
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets = resultQuery.ToArray();
Test(sets);

var source = Enumerable.Range(0, 10);
var sourceQuery = (
from x in source
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets2 = sourceQuery.ToArray();
Test(sets2);
}

static void Test(Set[] sets)
{
var f = sets[0].Field;
Console.WriteLine(sets.All(x => object.Equals(x.Field, f)));
var p = sets[0].Property;
Console.WriteLine(sets.All(x => object.Equals(x.Property, p)));
Console.Writeline(sets.Length);
Console.WriteLine(object.Equals(f, p));
Console.WriteLine();
}
}
Test() 的输出对于 LINQ to SQL 查询是
True
True
1362
False

这表明对于所有 Set制作的对象,所有 Field成员(member)指向同一个单 Entry实例和所有 Property成员(member)指向同一个单 Entry实例。即,在查询的每次迭代中,相同的实例被重新用于相应的成员。
Test() 的输出对于 LINQ to objects 查询是
False
False
10
False

这表明在查询的每次迭代中都会创建一个新的不同实例。

LINQ to SQL 行为是预期的还是错误?有谁知道 Entity Framework 是否会发生这种情况?

最佳答案

我不知道这是否是一个错误,或者是否以及为什么在 LINQ to SQL 中会出现这种情况。如果 Entity Framework 也发生这种情况,我只能回答你的最后一个问题。

答案是不。

使用 EF 时,您必须使用对象初始化器语法,但在实例化 Entry 时对象。使用默认构造函数会导致异常:

var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { Name = "X" },
Property = new Entry { Name = "X" }
}
);

你如何初始化并不重要。使用上面的代码(在一个小测试表中有 4 行),我通过您的测试程序得到了这个输出:
False
False
4
False

False
False
10
False

看起来 LINQ to SQL 和 Entity Framework 在投影期间的对象物化方面存在很大差异。

(我已经使用 EF 4.1/DbContext 进行了测试。)

编辑

如果我在上面的代码片段中将修改后的查询也用于您的 LINQ to SQL 查询并观察生成的 SQL,我会得到以下信息:
SELECT NULL AS [EMPTY]
FROM [dbo].[SomeTable] AS [t0]

而与 LINQ to Entites 相同的方法会创建此查询:
SELECT 
1 AS [C1],
N'X' AS [C2],
N'X' AS [C3]
FROM [dbo].[SomeTable] AS [Extent1]

我的解释是 LINQ to SQL 解析投影代码并仅查询依赖于“行变量”x 的属性值的列。当对象物化时,所有其他属性都在客户端上填充。如果对象完全不依赖于列值,LINQ to SQL 会创建一个常量对象并在整个结果集合中重用它。

与此 Entity Framework 相反,还将常量值(与 x 无关)发送到数据库服务器。这些值被发送回客户端,EF 将这些值视为列值并更新投影中对象的属性。

这也导致了这样的巨大差异......
Random random = new Random();
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { ID = random.Next() },
Property = new Entry { Name = "X" }
}
);

...在 LINQ to SQL 中工作,因为显然随机函数值(与 x 无关)在客户端上进行评估,然后分配给属性。但是 EF 希望将属性分配的右侧转换为 SQL 并将其作为 SQL 片段发送到数据库服务器 - 这失败并导致臭名昭著的“......无法转换为存储表达式......”异常。

编辑 2

顺便说一句:上面的最后一个代码片段仍然只创建一个 Field整个集合中的实例: random.Next()只计算一次(而且 Entry 的构造函数只为 Field 对象调用一次)。这现在确实令人困惑,因为编写这样的代码会期望您希望从数据库返回的每一行都有一个随机值。事实并非如此。

关于entity-framework - 在 LINQ to SQL 查询中使用了 'new' 运算符,但在每个结果中都引用了相同的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9640270/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com