Сначала составной шаблон с кодом Entity Framework 4.1 - PullRequest
0 голосов
/ 27 июля 2011

Мне нужно сначала представить составной шаблон с кодом 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 Ответ

1 голос
/ 28 июля 2011

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

Вы можете использовать нетерпеливую загрузку:

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

Этот запрос загрузит все композиты верхнего уровня и их компоненты прямого слоя (только один уровень!).

Вы также можете использовать отложенную загрузку, но все ваши навигационные свойства должны быть помечены как virtual. В этом случае EF создаст отдельный запрос для загрузки каждого свойства навигации после первого доступа. В иерархической структуре это может привести к большому количеству запросов к базе данных.

Полагаю, у вас будет много других проблем с вашим кодом. Например, если вы ожидаете, что все три слоя будут использовать одни и те же компоненты, они не будут - каждый компонент будет добавлен три раза, а если ключ представляет его первичный ключ, он будет иметь другое значение.

Вероятно, вам следует прочитать немного об EF и о том, как он работает, прежде чем приступить к выполнению сложного отображения, иначе у вас будет много проблем.

...