首先是Entity Framework 4.1代码的复合模式

时间:2011-07-27 15:56:40

标签: entity-framework entity-framework-4.1 ef-code-first code-first

我需要先用Entity Framework代码表示复合模式。如何实现这一目标?    我已经阅读了一篇关于使用访问者模式的帖子,但我认为应该使用Fluent API轻松完成并且不太复杂,但我不知道如何。

它可以正确保存数据库中的数据,但是当我尝试再次加载它时会带来错误的数据。

var components = from p in ctx.LayerComponents.Include("ComponentsLayer").Include("Component") select p;

foreach (var p in components)
{
    Trace.WriteLine("------------------------------------------------------------------------------------------------");
    p.Apply();
}

到目前为止,这是我的模型:

public abstract class LayerComponents
{
    public LayerComponents()
    {
        Components = new List<Component>();
    }

    [Key]
    public int Id { get; set; }
    public string Description { get; set; }

    public ICollection<Component> Components { get; set; }
    public abstract void Apply();
    public abstract void AddLayer(LayerComponents component);
    public abstract void RemoveLayer(LayerComponents component);
    public abstract void AddComponent(Component component);
}

public class CompositeLayerComponents : LayerComponents
{
    public ICollection<LayerComponents> ComponentsLayer { get; set; }
    public int? ParentID { get; set; }
    public CompositeLayerComponents Parent { get; set; }

    public CompositeLayerComponents()
    {
        ComponentsLayer = new List<LayerComponents>();
    }

    public override void ApplyComponents()
    {
        foreach (LayerComponents lp in ComponentsLayer)
        {
            lp.ApplyComponents();
        }
        Trace.WriteLine("Inside: " + Description);
        foreach (var p in Components)
        {
            Trace.WriteLine("       Applying component: " + p.Key.ToString() + "-" + p.Value.ToString());
        }
        Trace.WriteLine("Done Applying Components in " + Description + Environment.NewLine);
    }

    public override void AddLayer(LayerComponents component)
    {
        ComponentsLayer.Add(component);
    }

    public override void RemoveLayer(LayerComponents component)
    {
        ComponentsLayer.Remove(component);
    }

    public override void AddComponent(Component component)
    {
        this.Components.Add(component);
    }
}

public class LeafLayerComponents : LayerComponents
{
    public override void ApplyComponents()
    {
        Trace.WriteLine("Inside: " + Description);
        foreach (var p in Components)
        {
            Trace.WriteLine("       Applying component: " + p.Key.ToString() + "-" + p.Value.ToString());
        }
        Trace.WriteLine("Done Applying Components in " + Description + Environment.NewLine);
    }

    public override void AddLayer(LayerComponents component)
    {
        throw new Exception("Can't add a layer to the LeafLayerComponents");
    }

    public override void RemoveLayer(LayerComponents component)
    {
        throw new Exception("Can't add a layer to the LeafLayerComponents");
    }

    public override void AddComponent(Component component)
    {
        Components.Add(component);
    }
}

public class Component
{
    [Key]
    public int Id { get; set; }
    [Required]
    protected string Description { get; set; }

    [Required]
    public int KeyValue { get; set; }

    [Required]
    public string Value { get; set; }
    [Required]
    public Guid userId { get; set; }
}

问题在于,当我加载数据库记录时,它无法在内存中再次正确映射。例如: 如果我保存这个

    root = new CompositeLayerComponents { Description = "root" };

        // Set building preferences
        var buildingComponentsLayer = new CompositeLayerComponents { buildingId = Guid.NewGuid(), Description = "buildingComponents" };
        buildingComponentsLayer.AddComponent(new Component { Key = 0, Value = "Concept2" });
        buildingComponentsLayer.AddComponent(new Component { Key = 1, Value = "1" });
        buildingComponentsLayer.AddComponent(new Component { Key = 2, Value = "true" });

        var floor1LayerComponents = new CompositeLayerComponents { Description = "floor1Components" };
        floor1LayerComponents.AddComponent(new Component() { Key = 0, Value = "Concept1" });
        floor1LayerComponents.AddComponent(new Component() { Key = 1, Value = "2" });
        floor1LayerComponents.AddComponent(new Component() { Key = 2, Value = "true" });

        var floor2LayerComponents = new CompositeLayerComponents { Description = "floor2Components" };
        floor2LayerComponents.AddComponent(new Component() { Key = 0, Value = "Concept1" });
        floor2LayerComponents.AddComponent(new Component() { Key = 1, Value = "2" });
        floor2LayerComponents.AddComponent(new Component() { Key = 2, Value = "false" });

        var officeComponentsLayer = new LeafLayerComponents { Description = "officeComponents" };
        officeComponentsLayer.AddComponent(new Component() { Key = 0, Value = "Concept1" });

        buildingComponentsLayer.AddComponentLayer(floor1LayerComponents);
        floor2LayerComponents.AddComponentLayer(officeComponentsLayer);
        buildingComponentsLayer.AddComponentLayer(floor2LayerComponents);
        root.AddComponentLayer(buildingComponentsLayer);

        ctx.LayerComponents.Add(root);
        ctx.SaveChanges();

它不会加载一个根层,其中一个buildingLayerComponent在其中有2个FloorLayerComponents,其中一个floorLayerComponents有一个officeLayerComponent。这就是问题,如何再次加载该层次结构。

1 个答案:

答案 0 :(得分:1)

很难跟随你的代码,因为它甚至不可编译但是如果你的问题是它没有加载整个层次结构那么它就不是一个问题它是一个特征。 EF不会自动加载关系。你必须告诉它这样做,而在层次结构中它实际上非常困难。

您可以使用预先加载:

var root = context.LayerComponents.OfType<CompositeLayerComponsnts>().Include(c => c.ComponentsLayer).Where(c => c.ParentId == null);

此查询将加载所有顶级复合材料及其直接图层组件(仅限单个级别!)。

您也可以使用延迟加载,但所有导航属性都必须标记为virtual。在这种情况下,EF将创建单独的查询,以便在第一次访问时加载每个导航属性。在分层结构中,这可能导致大量数据库查询。

我希望你的代码还有很多其他问题。例如,如果您希望所有三个层都使用相同的组件,那么它们将不会添加三次,如果key代表其主键,它将具有不同的值。

在开始进行复杂的映射之前,您可能应该阅读一些关于EF及其工作原理的内容,否则会遇到很多麻烦。