实体框架6在预先加载

时间:2015-09-11 18:37:49

标签: .net entity-framework orm entity-framework-6 one-to-many

实体框架正在加载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);

因此,Polygon和LineSegments都有一个表,它们可以在LineSegment引用多边形的位置正确插入。但是当我尝试使用预先加载来检索它们时,它不会加载列表。我在包含中列出了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的链接,说明了我的问题。

  1. 克隆它。
  2. 初始化项目根目录中的子模块(git submodule initgit submodule update)(如果您使用SourceTree,这可能会自动发生)
  3. 运行PostgreSQL脚本,注意由于它正在创建数据库,因此无法一次性运行它。按照顶部的评论。
  4. 运行单元测试,并注意除了InsertAndRetrievePolygon之外它们都应该通过。那是因为没有检索List,你可以通过将鼠标悬停在调试器中的变量上看到。
  5. 希望这有助于理解,诊断和解决这个问题。您会注意到,在我的问题中,我简化了GeometryClassLibrary中实际存在的层次结构。谢谢,Scott H

3 个答案:

答案 0 :(得分:3)

这是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() - Edges代替LineSegments解决此问题,因为这是Edges的代码:

protected List<IEdge> _Edges = new List<IEdge>();
public virtual List<IEdge> Edges
{
    get { return _Edges; }
    set { _Edges = value; }
}

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

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

答案 1 :(得分:1)

尝试更改您的课程如下:

public class Polygon
{
    public virtual List<LineSegment> LineSegments
    {
        get;
        set;
    }


    // ...
}

在您的查询中,仅包含导航属性。不应包括字符串,原始类型和枚举类型。像这样:

var dataSet = databaseContext.Set<Polygon>();
Polygon retrievedObject = dataSet.Include(i => i.LineSegments).SingleOrDefault(match);

return retrievedObject;

这对你有用吗?

答案 2 :(得分:0)

我在这里看一下Code First中关于一对多关系的第一个例子。 http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx

我认为Fabio Luz走在正确的轨道上。 LineSegments集合应该是虚拟的。您还可以尝试重写默认构造函数并实例化该属性。此外,LineSegments类中的Polygon可能应该有一个虚拟属性来完成引用关系。

public class Polygon 
{
    public Polygon()
    {
        LineSegments = new List<LineSegment>();
    }

    public virtual List<LineSegment> LineSegments
    {
        get;
        set;
    }


    // ...
}

public class LineSegment
{
   public virtual Polygon Polygon { get; set; }
}