使用 LINQ to Entities 进行数据绑定时出现重复行

问题描述 投票:0回答:4

我在将 telerik RadGrid 和普通 ASP.NET GridView 绑定到以下 LINQ to 实体查询的结果时遇到问题。在这两种情况下,网格都包含正确的行数,但仅前几行的数据会在所有其他行中重复。我直接将此代码的返回值分配给网格上的 DataSource 属性。

public IEnumerable<DirectoryPersonEntry> FindPersons(string searchTerm)
{
    DirectoryEntities dents = new DirectoryEntities();
    return from dp in dents.DirectoryPersonEntrySet
           where dp.LastName.StartsWith(searchTerm) || dp.Extension.StartsWith(searchTerm)
           orderby dp.LastName, dp.Extension
           select dp;
}

这是有效的替代纯 ADO.NET 代码:

    DataTable ret = new DataTable();
    using (SqlConnection sqn = new SqlConnection(ConfigurationManager.ConnectionStrings["WaveAdo"].ConnectionString))
    {
        SqlDataAdapter adap = new SqlDataAdapter("select * from DirectoryPersonList where LastName like '" + searchTerm + "%' order by LastName ", sqn);
        sqn.Open();
        adap.Fill(ret);
    }
    return ret;
  1. 通过 LINQ 发送到 SQL Server 的查询有效。
  2. 在返回 LINQ 查询结果之前对其进行迭代会导致相同的重复。
  3. 在绑定之前,在调用方法中迭代 LINQ 结果会导致相同的重复。

根据下面 Marc Gravel 提供的非常合乎逻辑且合适的建议,我发现 EF 设计者对我的实体类的实体键做出了错误的猜测:其字段列表中的第一个字段是 Department,其中只有大约七个条目在所有其他记录中共享。

这确实是重复的原因。如果我可以更改或删除实体密钥就好了,但我不能。

.net asp.net linq
4个回答
32
投票

在我看来,你的主键坏了。 LINQ-to-SQL 和 EF 的“身份管理”方面意味着,每当它看到相同对象类型的相同主键值时,它就有义务返回相同的实例。

例如,给定数据:

id     | name       | ...
-------+------------+------
1      | Fred       | ...
2      | Barney     | ...
1      | Wilma      | ...
1      | Betty      | ...

然后 如果在从 LINQ 迭代对象时认为

id
是主键,则强制给你“Fred”、“Barney”、“Fred”、“Fred”。本质上,当它再次看到
id
1 时,它甚至不会查看其他列 - 它只是从身份缓存中获取具有
id
1 的实例 - 并为您提供之前为您提供的相同 Fred 实例。如果它认为
id
是主键,它会将每一行视为一个单独的对象(如果其中一个字段中的值与另一条记录相同怎么办 - 这并不罕见).

我建议检查您标记为主键(在 DBML/EDM 模型中)的任何字段确实每行都是唯一的。在上面的例子中,

id
列显然不代表唯一标识符,因此不适合作为主键。只需在 LINQ-to-SQL / EF 设计器中取消标记即可。


更新:特别是,请查看设计器中各种属性的“Entity Key”属性 - 特别是在查询视图时。检查“Entity Key”是否仅针对合适的列(即使行唯一的列)设置为 true。如果设置不正确,则设置为 false。这也显示为黄色钥匙图标 - 这只应该出现在真正是记录唯一标识符的事物上。


1
投票

如果将链接查询括在括号中并使用 .Distinct() 扩展名?

public IEnumerable<DirectoryPersonEntry> FindPersons(string searchTerm)
{
    DirectoryEntities dents = new DirectoryEntities();
    return (from dp in dents.DirectoryPersonEntrySet
           where dp.LastName.StartsWith(searchTerm) || dp.Extension.StartsWith(searchTerm)
           orderby dp.LastName, dp.Extension
           select dp).Distinct();
}

0
投票

工作查询和损坏查询之间的一个区别是 orderby 子句。我在 Linq to Entities 的 orderby 实现中发现了一个已记录的错误...可能还有其他错误。

尝试从损坏的查询中删除 orderby 并查看是否仍然得到重复项。

另一个区别是 where 子句中的 OR。尝试仅使用第一部分 [ where dp.LastName.StartsWith(searchTerm) ] 并查看是否仍然出现重复项。


0
投票

我遇到了同样的问题并通过解决方法解决了它。我将其发布在这里,因为它可能会帮助其他来到这里的人。

不要选择 dp ,而是使用

select new <ObjectName>
{
a = v.a
b = v.b
}.

这不会返回重复项。

© www.soinside.com 2019 - 2024. All rights reserved.