【问题标题】:Explicit Loading of child navigation properties with criteria使用标准显式加载子导航属性
【发布时间】:2012-12-17 13:32:07
【问题描述】:

在 EF5 中使用 DBContext - 根据日期范围等条件进行过滤和部分加载之后。

我正在尝试生成一个完整的图形或对象树 - Persons->Events where the only Events that are included are within a date range. 所有这些同时保留通过以下方式获得的标准更改跟踪:

 Dim Repository As Models.personRepository = New Models.personRepository

 Private Sub LoadData()
    Dim personViewModelViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("personViewModelViewSource"), System.Windows.Data.CollectionViewSource)
    Repository.endDate = EndDate.SelectedDate
    Repository.startDate = StartDate.SelectedDate
    personViewModelViewSource.Source = Repository.collectionOfpersons
 End Sub

列表框和数据网格都绑定为适当的数据源。 POCO 模板已修改为将 INotifyProperty 事件放入导航属性类 Events 中。

我已经为此奋斗了好几天,并且无论是在延迟加载还是显式加载上进行过滤都不起作用。 在大量阅读博客/章节之后,我意识到与 Include 相关的相当不真实的限制; 相反,我正在尝试显式加载。顺便说一句,我正在使用 DBContext 书。

无法从数据库中只取回部分事件数据是 100% 的交易破坏者,因为每个人可能有数十万个事件。 对于我或我的老板来说,Entity Framework 没有使这个功能相当明显是没有意义的——我们是否遗漏了什么?

我在注释代码中留下了尝试说明我尝试过的一些路径。类本身就是该方法所属的存储库。我将进一步编辑这个问题,以澄清我尝试了多少条路线,因为它已经很多了。 View 使用存储库层和 ViewModel,因此 XAML 背后的代码非常少。

提前寻求帮助,谢谢!

 Public Overridable ReadOnly Property AllFiltered(startdate As Date, enddate As Date) As ObservableCollection(Of person) Implements IpersonRepository.AllFiltered
        Get
            Dim uow = New UnitOfWork
            context = uow.Context
            Dim personQuery = context.persons.Include(Function(p) p.events).AsQueryable.Where(Function(x) x.personID = 10).FirstOrDefault


            'Dim eventQuery = From e In context.Notes
            '                 Where e.eventDateTime >= startdate And e.eventDateTime <= enddate
            '                 Select e

            'Dim personQuery As person = From r In context.persons
            '                   From e In eventQuery
            '                   Where r.personID = e.personID
            '                   Select r, e

            Dim singleperson = personQuery

            'For Each r As person In personQuery
            '    persons.Add(r)
            'Next

            '   context.Entry(eventQuery).Collection()
            ' context.Entry(personQuery).Reference(personQuery).Load()

            context.Entry(singleperson).Collection(Function(d) d.events).Query().Where(Function(x) x.eventDateTime > startdate And x.eventDateTime < enddate).Load()

            Return context.persons.Local
        End Get
    End Property

注意:我通过 PostSharp 使用日志记录/异常处理,而不是污染代码。

以下是我使用以前的路径产生的一些错误。

实体类型 DbQuery`1 不是当前上下文模型的一部分。

包含路径表达式必须引用在类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用 Select 运算符。

参数名称:路径

无法转换类型为“System.Data.Entity.Infrastructure.DbQuery1[VB$AnonymousType_02”的对象 [Entity.Person,Entity.Notes]]' 输入'System.Collections.ObjectModel.ObservableCollection`1[Entity.Person]'。

更新:我尝试过的另一条路线仍然无法飞行:

Private Property _collectionOfPersons As ObservableCollection(Of Person)

Public ReadOnly Property collectionOfPersons As ObservableCollection(Of Person)
        Get
            For Each Person In context.Persons
                _collectionOfPersons.Add(ReturnSinglePerson(startDate, endDate, Person.PersonID))
            Next
            Return _collectionOfPersons.Where(Function(x) x.events.Where(Function(e)         e.eventDateTime > startDate And e.eventDateTime < endDate))
        End Get
    End Property

Public Overridable ReadOnly Property SinglePerson(startdate As Date, enddate As Date) As ObservableCollection(Of Person) Implements IPersonRepository.AllFiltered
        Get

            Dim PersonQuery = context.Persons.Include(Function(p) p.events).AsQueryable.Where(Function(x) x.PersonID = 10).Select(Function(x) x).FirstOrDefault

            Dim Person = PersonQuery

            context.Entry(Person).Collection(Function(d) d.events).Query().Where(Function(x) x.eventDateTime > startdate And x.eventDateTime < enddate).Load()

            Return context.Persons.Local
        End Get
End Property

Public Function ReturnSinglePerson(startdate As Date, enddate As Date, id As Integer)

        Dim PersonQuery = context.Persons.Include(Function(p) p.events).AsQueryable.Where(Function(x) x.PersonID = id).Select(Function(x) x).FirstOrDefault
        Dim Person = PersonQuery
        Return Person

End Function

另一个镜头: 公共可重写只读属性 FilteredPersons(startdate As Date, enddate As Date) As ObservableCollection(Of Person) 实现 IPersonRepository.AllFiltered 得到 context.Persons.Load() Dim DateCriteria = Function(e) e.events.Where(Function(d) d.eventDateTime > startdate And d.eventDateTime

            Dim Res = New ObservableCollection(Of Person)
            For Each Person In context.Persons.Local.Select(Function(x) x).Where(DateCriteria)
                Res.Add(Person)
            Next

            Return Res
        End Get
    End Property

给予:

未找到类型“ObservableCollection(Of DailyNotes)”上的公共成员“Where”。

非常接近,只有我在列表框中得到了很多重复的名称 - 但导航通过并且日期标准有效。

   <ExceptionAspect>
    Public Overridable ReadOnly Property FilteredPersons(startdate As Date, enddate As Date) As ObservableCollection(Of Person) Implements IPersonRepository.AllFiltered
        Get
            context.Persons.Load()


            Dim test = From r In context.Persons
                    From e In context.Notes
                    Where e.eventDateTime > startdate And e.eventDateTime < enddate
                    Join rr In context.Persons On e.PersonID Equals rr.PersonID
                    Select r, e


            Dim Res = New ObservableCollection(Of Person)
            For Each Person In test
                Res.Add(Person.r)
            Next

            Return Res
        End Get
    End Property

不要尝试这个:)。它只选择子属性。

    Public ReadOnly Property collectionOfResidents As ObservableCollection(Of resident)
        Get
            For Each resident In context.residents
                _collectionOfResidents.Add(ReturnSingleResident(startDate, endDate, resident.residentID))
            Next
            Return _collectionOfResidents.Select(Function(x) x.events.Where(Function(e) e.eventDateTime > startDate And e.eventDateTime < endDate))
        End Get
    End Property

我希望在这个问题中添加我的其他尝试可以提示其他答案并帮助其他人在第一次解决这个问题时看到他们可以进入的圈子!

【问题讨论】:

    标签: entity-framework entity criteria dbcontext navigation-properties


    【解决方案1】:

    您可以使用Select 子句进行比Include 更精细的控制

    类似这样的:

    context
      .Persons
      .Where( ... some predicate on Person ... )
      .Select( o => new
        {
          Person = o,
          Events = o.Events.Where( ... some predicate on Event ... )
        }
      )
    ;
    

    这会将两个谓词转换为在数据库服务器上执行的 SQL。

    【讨论】:

    • 我试图将它翻译成 VB 并带有很大的失败 LOL,语法不希望发生。我不认为我可以在 VB 中执行此方法 :( 感谢您的建议,我现在仍在尝试。
    • 我现在有了更进一步的了解:
    • 如果匿名类型比较困难,您可以为选择的结果声明一个类。但是你必须使用默认的构造函数和对象初始化器。
    • 我已经走到了这一步,但遗憾的是它不对;它越来越近了。 code Dim test = From r In context.residents From e In context.DailyOccurrences.Select(Function(x) x).Where(Function(s) s.eventDateTime > startdate And s.eventDateTime
    • 我认为我们倾向于不使用 EF5,因为我已经连续使用了大约三周时间,虽然我已经成功地拥有了一个直接的界面,并且存储库完全可以正常工作由此——我完全无法用这种技术获得任何合理的标准选择方法。我唯一能做的就是手动做所有事情,忘记大部分绑定和 EF 优点。当我发现我可以轻松地完成原始项目时,我非常兴奋——拖放。但这部分太难了,我看不出我们可以使用它。 :(
    【解决方案2】:

    好吧,在今晚对匿名类型进行了很多摆弄和误解之后,我想我成功了。 Nicholas 的回答只需要在 VB 中完成,这花了我一段时间——我以前没有使用过匿名类型。

    这似乎在我的存储库层中运行良好:

                   <ExceptionAspect>
        Public Overridable ReadOnly Property FilteredPersons(startdate As Date, enddate As Date) As ObservableCollection(Of Person) Implements IPersonRepository.AllFiltered
            Get
                context.Persons.Load()
    
                Dim test = context.Persons.Where(Function(r) r.PersonActive).Select(Function(o) New With { _
                     .Person = o, _
                     .events = o.events.Where(Function(e) e.eventDateTime > startdate) _
                })
    
    
                Dim PersonList= New ObservableCollection(Of Person)
    
                For Each t In test
                   PersonList.Add(t.person)
                Next
    
                Return PersonList
            End Get
        End Property
    

    wpf 视图中的关键更新/保存完好无损,我非常高兴并感谢 Nicholas 在这里提供的帮助(以及耐心...re:cartesion 产品)。所以谢谢。我希望这对其他人有帮助!

    【讨论】:

    • 看起来好多了 - 抱歉我不会说 VB!但是,您不应该需要context.Persons.Load(),并且您必须在创建PersonList 时将匿名类型.Events 属性中的数据附加到Person 对象。如果这没有意义,请在名单外联系我。
    • @NicholasButler - 谢谢,我已经开始工作,发现视图部分根本没有刷新,但这是一个完全不同的问题,因为生成的 SQL 完全正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2016-11-21
    • 1970-01-01
    • 2016-12-21
    相关资源
    最近更新 更多