2013-03-16 96 views
2

我有问题EF 5和延迟加载循环引用。实体框架5循环延迟加载原因OutOfMemoryException

下图代表我的模型。 enter image description here

主要问题是Model和ModelProperties类之间,因为Model包含IEnumerable导航属性,而ModelProperty包含Model导航属性。

所以这样的设计会导致以下 enter image description here

的情况,您可以访问全尺寸图像http://tinypic.com/r/2vskuxl/6

你可以想象这会引起非常大的问题,内存溢出的例外。

只有我能找到的解决方案是禁用延迟加载和使用其他方法。但延迟加载非常简化我们的工作。 我希望有一个配置或一个属性来帮助我加载只有两个级别的关系与延迟加载。

有什么办法可以达到这个目的吗?

更新: 关于Julie Lerman的要求,这里是EF的视觉模型。 我突出了造成问题的主要关系。 这里是模型定义: enter image description here 您也可以在http://tinypic.com/r/30v15pg/6

更新2获得全尺寸。

public class Model { 
     public int ModelID { get; set; } 
     public int BrandID { 
      get; 
      set; 
     } 
     public virtual Brand Brand { get; set; } 
     public string Logo { get; set; } 
     public string Name { get; set; } 
     public virtual ICollection<ModelProperty> ModelProperties { 
      get; 
      set; 
     } 
} 

public class ModelProperty { 

    public int ModelPropertyID { 
     get; 
     set; 
    } 

    public virtual int PropertyDefinitionID { 
     get; 
     set; 
    } 

    public virtual PropertyDefinition PropertyDefinition { 
     get; 
     set; 
    } 

    public virtual int ModelID { 
     get; 
     set; 
    } 

    public virtual Model Model { 
     get; 
     set; 
    } 

    public bool IsContainable { 
     get; 
     set; 
    } 

    public bool HasFilterDefinition { 
     get; 
     set; 
    } 

    public virtual ICollection<ModelPropertyValue> ModelPropertyValues { 
     get; 
     set; 
    } 

    public virtual ICollection<ModelPropertyMatchingFilter> ModelPropertyMatchingFilter { 
     get; 
     set; 
    } 
} 

此外还有ModelProperty的实体配置。

public class ModelPropertyEntityTypeConfiguration : EntityTypeConfiguration<ModelProperty> { 
     public ModelPropertyEntityTypeConfiguration() { 
      HasKey(p => p.ModelPropertyID); 

      HasRequired(p => p.PropertyDefinition).WithMany(s => s.ModelProperties).HasForeignKey(s => s.PropertyDefinitionID).WillCascadeOnDelete(false); 
      HasRequired(p => p.Model).WithMany(s => s.ModelProperties).HasForeignKey(s => s.ModelID).WillCascadeOnDelete(false); 
      HasMany(p => p.ModelPropertyValues).WithRequired(s => s.ModelProperty).HasForeignKey(s => s.ModelPropertyID).WillCascadeOnDelete(true); 
      HasMany(p => p.ModelPropertyMatchingFilter).WithRequired(s => s.ContainerModelProperty).HasForeignKey(s => s.ContainerModelPropertyID).WillCascadeOnDelete(false); 
      ToTable("dbo.ModelProperties"); 
     } 
    } 

更新3: 我不知道,但Automapper也可能导致此。由于实体框架配置文件告诉成千上万在运行时调用的Autommaper方法。

UPDATE 4: 这里是EFProf堆栈跟踪: enter image description here 您访问更大的版本http://tinypic.com/r/21cazv4/6

UPDATE 5 您可以在这里看到示例项目:https://github.com/bahadirarslan/AutomapperCircularReference 在样品中,你可以看到轻松不已通过Quick Watch循环。

+1

Bahadir,我猜你是先使用代码,所以没有EDMX看。您可以使用EF Power Tool来生成模型的可视化表示并在此共享它吗?如果你不知道如何使用这个工具,我会在这个视频的大约19:00演示它:http://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Entity-Framework-Tips-and-技巧#时间= 19m00s – 2013-03-17 00:32:27

+0

你可以显示一段导致“OutOfMemoryException”的代码吗?在快速查看中,您可以永久钻取,但您可以自行触发延迟加载。应用程序中的哪些代码或进程会导致问题? – 2013-03-17 08:56:48

+0

@JulieLerman我加了EF的视觉模型。我希望这有帮助。 – 2013-03-17 09:49:46

回答

1

感谢您的更新。你模特看起来很好。它绝对知道这只是一个1:*的关系。拉迪斯拉夫(和往常一样)是正确的。 LL不会导致问题......除了在序列化期间的一个地方。有没有机会让你的代码在服务中?通过常规的延迟加载,只有你明确提到的属性会被延迟加载。但在序列化过程中,序列化“提及”每个属性,因此它只是在整个图表中不断加载和加载属性,并导致循环依赖问题。有了服务,我们必须在返回数据之前关闭延迟加载(使用context.configuration.lazyloadingenabled = false)。因此,在服务方法中,您可以急切加载或延迟加载或显式加载以获取图形,但在返回结果之前禁用延迟加载。

+0

感谢您的回答。这很有趣,我认为不同。我有分离层,EF在DbCore,并且有通用存储库和UoW模式。在这些层上,有Domain Service类,顶部有Web API方法。那么我可以在哪里禁用延迟加载? – 2013-03-17 21:07:21

+0

我尝试了很多东西,但stil无法找到最佳解决方案。还有急切的加载比我想象的更有趣。 – 2013-03-17 22:13:51

+0

你可以使用类似Entity Framework分析器的东西,并确切地确定什么是触发延迟加载? – 2013-03-17 22:37:27

1

您应该禁用延迟加载以绕过代理对象,或者您应该将您需要的作为DTO返回。使用DTO是首选,因为隐藏您的域的细节

+0

感谢您的回答。实际上,我使用DTO并使用Automapper转换后从API返回它们。但我也需要这些关系在上层。但不是所有的人,一两级对我来说都合适。 – 2013-03-18 13:21:34