使用条件显式加载子导航属性

时间:2012-12-17 13:32:08

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

在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书btw。

由于每人可能有数十万个事件,因此无法从数据库中仅带回一部分事件数据是100%的交易破坏者。 对于我或我的老板来说,实体框架没有使这个功能变得相当明显是没有意义的 - 我们是否遗漏了什么?

我留下了评论代码,试图说明我尝试过的一些路径。类本身是此方法所属的存储库。我将进一步编辑这个问题,以澄清我尝试了多少路线,因为它很多。 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不是当前上下文模型的一部分。

Include路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为参考导航属性,使用Select运算符作为集合导航属性。

参数名称:路径

无法转换类型为'System.Data.Entity.Infrastructure.DbQuery 1[VB$AnonymousType_0的对象2 [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

另一个镜头:             Public Overridable ReadOnly属性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&gt; startdate and d.eventDateTime&lt; enddate)

            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

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

2 个答案:

答案 0 :(得分:1)

您可以使用Select子句进行更精细的控制,而不是使用Include

这样的事情:

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

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

答案 1 :(得分:0)

好的,今晚在对匿名类型的大量摆弄和误解之后,我想我成功了。 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 View中关键的更新/保存完好无损,我真的很高兴并感谢Nicholas在这里提供的帮助(以及耐心...... re:cartesion产品)。所以谢谢。我希望这有助于其他人!