【问题标题】:Unbelievable duplicate in an Entity Framework Query实体框架查询中令人难以置信的重复
【发布时间】:2011-02-14 15:53:58
【问题描述】:

针对特定视图的 SQL 查询返回 3 个不同的行。

 select * from vwSummary
 where vidate >= '10-15-2010' and vidate <= '10-15-2010'
 and idno = '0330'
 order by viDate

但是如果我通过我的实体框架运行相同的查询,我会得到 3 行,但所有 3 行都是相同的,相当于第三行。

        firstVisibleDate = new DateTime(2010, 10, 15);

        lastVisibleDate = new DateTime(2010, 10, 15);

var p1 = (from v in db.vwSummary
                     where v.viDate >= firstVisibleDate && v.viDate <= lastVisibleDate
                     && v.IDNo == "0330"
                          select v).ToList();

谁能帮我解决这个问题。

编辑: 我像这样更改了我的查询并且它有效。但是我仍然想回到上面显示的那个,因为我必须再次迭代以进行更多处理。

List<objectName> p1 = (from v in db.vwSummary
                     where v.viDate >= firstVisibleDate && v.viDate <= lastVisibleDate
                     && v.IDNo == "0330"
                          select new <ObjectName>
{
a = v.a
b = v.b
}
).ToList<ObjectName>();

【问题讨论】:

  • 有点疯狂的猜测,但可能是代码中定义的 DateTime 将时间包括为午夜,而 SQL 中定义的 DateTime 仅定义了日期。即您的 SQL 正在返回当天的所有内容,但代码正在返回午夜的所有内容。不知道为什么你会得到相同数量的结果。
  • 是的,这仍然让我感到困惑。我尝试使用日期时间,但找不到线索。
  • 我尝试重新构建实体模型,只是为了确保它们同步。还是没有成功。
  • 看看单独的 where 子句彼此相邻而不是 && 会发生什么。 where v.viDate &gt;= firstVisibleDate where v.viDate &lt;= lastVisibleDate where v.IDNo == "0330" 我不知道这是否会有所作为,但值得一试。
  • 我的猜测是问题在于你如何使用结果,而你没有显示出来。

标签: c# entity-framework sql-server-2008 duplicates


【解决方案1】:

我遇到了类似的问题,我通过更改 ObjectSet 的合并选项解决了它。 示例:

    using (TargetDBDataContext db = new TargetDBDataContext())
    {
        db.SomeView.MergeOption = System.Data.Objects.MergeOption.NoTracking;
        return db. SomeView.ToList();
    }

看起来实体框架 (EF) 无法正确处理具有重复主键或根本没有主键的视图。因此,当 EF 认为有两行相等时,EF 将按原样加载第一行,但不会加载第二行,因为它会认为它已经加载。

【讨论】:

  • 您也可以尝试将实体查询中的 db.SomeView 替换为 db.SomeView.AsNoTracking()。这对我来说适用于 EF5。
  • 我在视图中添加了一个主键,一切都很好。正如 OP 所说——“难以置信”是我看到问题时的感受。
  • MergeOption 在 EF 中似乎不再有效,需要改用 AsNoTracking()
  • 实体框架使用“身份映射”,每个 DbContext 的每个 id 最多构造一个实例。换句话说,同一 DbConext 中的两个单独的 Linq 查询“其中 id == 1”将返回实体的相同运行时实例。它基本上检查地图以查看是否已经构建了具有该 ID 的地图并将其返回。您加载的每个“实体”都会在上下文的更改跟踪器中进行跟踪(除非您调用 AsNoTracking 或返回匿名类型,例如 'select new { x.a, x.b }')。您不能使用非唯一键作为实体 ID,因为它们都将映射到同一个实例。
【解决方案2】:

Entity Framework 公开了许多性能调整选项来帮助您优化应用程序的性能。这些调整选项之一是 .AsNoTracking()。此优化允许您告诉 Entity Framework 不要跟踪查询的结果。这意味着实体框架不会对查询返回的实体执行额外的处理或存储。但是,这也意味着您无法更新这些实体而不将它们重新附加到跟踪图。

您可以直接在视图上设置 AsNoTracking 选项来解决此问题。

context.viewname.AsNoTracking().Where(x => x.ColumnName != null);

【讨论】:

    【解决方案3】:

    在视图的实体模型上设置实体键。这在两个不同的情况下对我有用。您可以在键中使用一个或多个属性。

    【讨论】:

      【解决方案4】:

      解决方法:我像这样更改了我的查询并且它有效。但是我仍然想回到上面显示的那个,因为我必须再次迭代以进行更多处理。

      List<objectName> p1 = (from v in db.vwSummary
                           where v.viDate >= firstVisibleDate && v.viDate <= lastVisibleDate
                           && v.IDNo == "0330"
                                select new <ObjectName>
      {
      a = v.a
      b = v.b
      }
      ).ToList<ObjectName>();
      

      我从herehere 找到了问题的根源。我猜这应该是一个问题,因为我认为我没有一个很好的关键,因为该视图更像是一个总结报告。所以我坚持我在其他答案中找到的解决方法。

      因此,如果您发现类似的问题,问题是,为您的表或视图添加适当的主键。如果你不能添加一个尝试类似的解决方法。

      【讨论】:

        【解决方案5】:

        我刚刚遇到了这个问题,并认为这是我的实现,直到我找到了这篇文章。我设法开始工作的唯一解决方法是实际运行 sqlquery,如下所示:-

        using(var db = new Tpr.Models.MyContext())
        {
            var model = _uow._context.Database.SqlQuery<MyTable>(string.Format("select * from MyTable where ID = '{0}'", "12345678"));
        
            Assert.IsNotNull(model);
        }
        

        【讨论】:

          猜你喜欢
          • 2018-11-16
          • 1970-01-01
          • 2011-12-06
          • 1970-01-01
          • 2019-07-21
          • 2011-12-18
          • 2023-03-20
          • 2019-06-05
          相关资源
          最近更新 更多