Вопрос

У меня есть иерархия EF, которая (значительно упрощенная) выглядит примерно так:

class Room { EntityCollection<Session> Sessions; }
class Session { EntityCollection<Whiteboard> Whiteboards; EntityReference Room; }
class Whiteboard { EntityCollection<WhiteboardShape> WhiteboardShapes; EntityReference Session; }
abstract class WhiteboardShape { EntityReference Whiteboard; }
class WhiteboardShapeEllipse : WhiteboardShape { }
class WhiteboardShapePolyline { WhiteboardShape { EntityCollection<PolylinePoint> PolylinePoints }
class PolylinePoint { EntityReference<WhiteboardShapePolyline> WhiteboardShapePolylineReference; }

Другими словами, комната может содержать несколько сеансов;каждый сеанс может содержать несколько досок;и каждая доска может содержать несколько фигур WhiteboardShapes.Эти фигуры могут быть разных типов, включая WhiteboardShapePolyline, которая сама может содержать несколько точек PolylinePoints.

Когда удаленный пользователь первоначально подключается к комнате, мне нужно передать этому пользователю весь граф объекта, и я пытаюсь выяснить, как максимально эффективно загрузить этот граф из базы данных в память.

Теперь, конечно, EF позволяет вам выполнять быструю загрузку, например:

      Room room = ctx.Room
            .Include("Sessions.Whiteboards")
            .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

Но Include() не позволяет мне загружать PolylinePoints.В частности, если я попробую:

        Room room = ctx.Room
            .Include("Sessions.Whiteboards.WhiteboardShape.PolylinePoint")
            .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

Я получаю исключение: «Указанный путь включения недействителен.EntityType «SlideLinc.Model.WhiteboardShape» не объявляет свойство навигации с именем «PolylinePoint».

И это не работает:

.Include("Sessions.Whiteboards.WhiteboardShapePolyline.PolylinePoint")

И это не так:

.Include("Sessions.Whiteboards.WhiteboardShape.WhiteboardShapePolyline.PolylinePoint")

Как и любой другой способ создания пути навигации, который я могу придумать.

То, как я это сделал, конечно кажется для меня как хак:

        // Make sure we've got everything loaded.
        if (room != null)
        {
            if (!room.Sessions.IsLoaded) { room.Sessions.Load(); }
            foreach (Session session in room.Sessions)
            {
                if (!session.Whiteboards.IsLoaded) { session.Whiteboards.Load(); }
                foreach (Whiteboard whiteboard in session.Whiteboards)
                {
                    if (!whiteboard.WhiteboardShape.IsLoaded) { whiteboard.WhiteboardShape.Load(); }
                    foreach (WhiteboardShape shape in whiteboard.WhiteboardShape)
                    {
                        if (shape is WhiteboardShapePolyline)
                        {
                            WhiteboardShapePolyline polyline = (WhiteboardShapePolyline)shape;
                            if (!polyline.PolylinePoints.IsLoaded) { polyline.PolylinePoints.Load(); }
                        }
                    }
                }
            }
        }

Это работает, но кода намного больше, чем мне нужно, и требуется гораздо больше обращений к базе данных, чем мне хотелось бы.

Самый близкий ответ, который я нашел, это здесь, но мой бедный мозг, изголодавшийся по Linq, не может понять, как перевести пример кода в более сложную иерархию, которая у меня есть;плюс, пример кода по этой ссылке чертовски уродлив и сложен для понимания.На самом деле я не хочу, чтобы вся моя иерархия объектов зависела от неясного и невидимого побочного эффекта того, как EF внутренне строит свои иерархии.

Есть еще предложения?

Это было полезно?

Решение

Я бы, наверное, использовал для этого проекцию.Вместо возврата типов сущностей проецируйте их на упрощенные объекты передачи данных или анонимные типы.При проецировании (например, с помощью запроса LINQ) загрузка происходит автоматически.В этом случае вам не нужно указывать Include.

Другие советы

У меня возникла проблема, аналогичная вашей (более простой путь навигации), и я понял, что имя свойства в файле Designer.cs не соответствует моим ожиданиям.Как только я изменил его на PropertyName в файле Designer, все заработало нормально - также обратите внимание, что я сделал два разных пути, которые стали:

.Include("UnexpectedNameA").Include("UnexpectedNameB")
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top