Entity Framework 正在加载 Polygon 中的所有内容,但我的 LineSegments 列表。我错过了什么?

多边形:

public class Polygon
{
    List<LineSegment> _lineSegments = new List<LineSegment>();
    public List<LineSegment> LineSegments
    {
        get { return _lineSegments; }
        protected set { _lineSegments = value; }
    }

    public Point BasePoint { get; protected set; }

    public Vector NormalVector { get; protected set; }

    public int? DatabaseId { get; set; }

    // ...
}

LineSegment 类( Polygon 有这些列表)
public class LineSegment
{
    public virtual Distance Magnitude
    {
        get { return _magnitude; }
        set { _magnitude = value; }
    }
    private Distance _magnitude;

    public virtual Point BasePoint
    {
        get { return _basePoint; }
        set { this._basePoint = value; }
    }
    private Point _basePoint;

    public virtual Direction Direction
    {
        get { return _direction; }
        set { _direction = value; }
    }
    private Direction _direction;

    public int? DatabaseId { get; set; }

    // ...
}

这是模型中的关系设置:
modelBuilder.Entity<Polygon>()
        .HasMany(polygon => polygon.LineSegments);

因此,多边形和线段都有一个表,它们正确插入到线段引用多边形的位置。但是当我尝试使用预先加载来检索它们时,它不会加载列表。我在包含中列出了 LineSegment 的属性,但它不起作用。我想我需要修改模型中的关系设置,但我不确定如何修改。 如何更正此问题,以便在加载多边形时立即加载 LineSegments 列表? 这是查询:
    private static List<Expression<Func<Polygon, object>>> polygonRegionNaviationProperties = new List<Expression<Func<Polygon, object>>>()
    {
        (polygon => polygon.BasePoint),
        (polygon => polygon.BasePoint.X),
        (polygon => polygon.BasePoint.Y),
        (polygon => polygon.BasePoint.Z),
        (polygon => polygon.NormalVector),
        (polygon => polygon.NormalVector.Direction),
        (polygon => polygon.NormalVector.Direction.Phi),
        (polygon => polygon.NormalVector.Direction.Theta),
        (polygon => polygon.NormalVector.Magnitude),
        (polygon => polygon.NormalVector.BasePoint.X),
        (polygon => polygon.NormalVector.BasePoint.Y),
        (polygon => polygon.NormalVector.BasePoint.Z),
        (polygon => polygon.LineSegments),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.Direction)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.Direction.Phi)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.Direction.Theta)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.Magnitude)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.BasePoint.X)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.BasePoint.Y)),
        (polygon => polygon.LineSegments.Select(lineSegment => lineSegment.BasePoint.Z))
    };

    public Polygon GetPolygon(int? databaseId)
    {
        if(databaseId != null)
        {
            Polygon retrievedPolygon = Query((polygon => polygon.DatabaseId == databaseId), polygonRegionNaviationProperties);
            return retrievedPolygon;
        }
        else
        {
            return null;
        }
    }

    public override Polygon Query(Expression<Func<Polygon, bool>> match, List<Expression<Func<Polygon, object>>> includes = null)
    {
        using (var databaseContext = new ClearspanDatabaseContext())
        {
            databaseContext.Database.Log = Console.Write;

            if (includes != null)
            {
                var dataSet = databaseContext.Set<Polygon>(); // Get the relevant DataSet
                Polygon retrievedObject = includes.Aggregate( // Eagerly load the passed navigation properties
                        dataSet.AsQueryable(),
                        (current, include) => current.Include(include)
                    ).SingleOrDefault(match);
                databaseContext.Entry(retrievedObject).Collection(polygon => polygon.LineSegments).Load();
                return retrievedObject;
            }
            else
            {
                Polygon retrievedObject = databaseContext.Set<Polygon>().SingleOrDefault(match);
                databaseContext.Entry(retrievedObject).Collection(polygon => polygon.LineSegments).Load();
                return retrievedObject;
            }
        }
    }

更新

这是一个链接到一个细化的 project 说明我的问题。
  • 克隆它。
  • 初始化子模块(项目根目录下的 git submodule initgit submodule update)(如果你使用 SourceTree,这可能会自动发生)
  • 运行 PostgreSQL 脚本,注意你不能一次运行它,因为它正在创建一个数据库。按照顶部的评论。
  • 运行单元测试,注意除了 InsertAndRetrievePolygon 之外,它们都应该通过。这是因为没有检索到列表,您可以通过将鼠标悬停在调试器中的变量上来查看。

  • 希望这有助于理解、诊断和解决这个问题。您会注意到,在我的问题中,我简化了 GeometryClassLibrary 中实际存在的层次结构。谢谢,斯科特 H

    最佳答案

    这是 Polygon.LineSegments 的代码:

    public virtual List<LineSegment> LineSegments
    {
        get { return this._Edges.Select(e => (LineSegment)e).ToList(); }
        set { _Edges = value.ToList<IEdge>(); }
    }
    

    当 EF 填充子集合时,它不会为其分配一个完整的集合,而是在必要时对其进行初始化,然后向其中添加项目。现在这里是陷阱:EF 向哪个集合添加项目?不是 _Edges ,而是每次 ToList() 被寻址时由 LineSegments 构建的临时集合。 _Edges 本身仍然是空的。

    不幸的是,你不能通过 Include() -ing Edges 而不是 LineSegments 来解决这个问题,因为这是 Edges 的代码:
    protected List<IEdge> _Edges = new List<IEdge>();
    public virtual List<IEdge> Edges
    {
        get { return _Edges; }
        set { _Edges = value; }
    }
    

    EF 不支持接口(interface)。坦率地说,我不知道是否有像样的解决方法。 LineSegments 中的这种间接性可能会导致 EF 出现更多问题。例如,我认为关系修复(从加载到上下文中的实体自动填充导航属性)也不会运行。

    我知道这些类来自外部库。我在那里看到所有这些 XyzEntityFramework 部分类(例如 LineSegmentEntityFramework ),它们似乎添加了属性以方便使用 EF。也许他们愿意查看您的问题并找到解决方案。

    关于.net - Eager Load 上的 Entity Framework 6 加载列表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32530093/

    10-11 06:32
    查看更多