Entity Framework,为多层层次结构的简单迭代和通用引用设置

Entity Framework, Setup for easy iteration and generic referencing of multi-level hierarchy

我有一个 entity framework 模型设置如下:

-TblProject
--TblLine
---TblGroup
----TblStation
-----TblDevice
------TblSubDevice
-------TblSubSubDevice

这些 class 中的每一个都实现了一个包含 ID、名称和类型属性的 BaseTable。我可以将我的任何实体转换为 BaseTable 并访问这些属性。

我有这样一种情况,我一直不得不编写重复的代码,因为每个 class 都是不同的类型,例如,请参阅此排序函数:

        public static void OrderTreeSetup(ObservableCollection<tblProject> Table, System.ComponentModel.ListSortDirection direction)
    {
        ICollectionView ParentTable = CollectionViewSource.GetDefaultView(Table);
        ParentTable.SortDescriptions.Clear();
        ParentTable.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
        foreach (tblProject Project in Table)
        {
            ICollectionView Projects = CollectionViewSource.GetDefaultView(Project.tblLines);
            Projects.SortDescriptions.Clear();
            Projects.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
            foreach (tblLine Line in Project.tblLines)
            {
                ICollectionView Lines = CollectionViewSource.GetDefaultView(Line.tblGroups);
                Lines.SortDescriptions.Clear();
                Lines.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
                foreach (tblGroup Group in Line.tblGroups)
                {
                    ICollectionView Groups = CollectionViewSource.GetDefaultView(Group.tblStations);
                    Groups.SortDescriptions.Clear();
                    Groups.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
                    foreach (tblStation Station in Group.tblStations)
                    {
                        ICollectionView Stations = CollectionViewSource.GetDefaultView(Station.tblDevices);
                        Stations.SortDescriptions.Clear();
                        Stations.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
                        foreach (tblDevice Device in Station.tblDevices)
                        {
                            ICollectionView Devices = CollectionViewSource.GetDefaultView(Device.tblSubDevices);
                            Devices.SortDescriptions.Clear();
                            Devices.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
                            foreach (tblSubDevice SubDevice in Device.tblSubDevices)
                            {
                                ICollectionView SubDevices = CollectionViewSource.GetDefaultView(SubDevice.tblSubSubDevices);
                                SubDevices.SortDescriptions.Clear();
                                SubDevices.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", direction));
                            }
                        }
                    }
                }
            }

        }
    }

如何更改我的 entity framework 模型以提供更通用的编程方法?

您的代码确实有优化的空间(正如您看到这么多重复代码时所期望的那样)。这甚至可以用相对较少的努力完成。

让我们从容易实现的目标开始:由于 CollectionViewSource.GetDefaultView 接受类型为 object 的参数,您可以替换您的初始化代码...

ICollectionView ParentTable = CollectionViewSource.GetDefaultView(Table);
ParentTable.SortDescriptions.Clear();
ParentTable.SortDescriptions
    .Add(new System.ComponentModel.SortDescription("Name", direction));

...调用此方法:

private static void ConfigureSorting(object entity, ListSortDirection direction)
{
    ICollectionView view = CollectionViewSource.GetDefaultView(entity);
    view.SortDescriptions.Clear();
    view.SortDescriptions.Add(new SortDescription("Name", direction));
}

这将使您的初始化代码看起来更清晰,并避免代码重复部分的维护问题:

public static void OrderTreeSetup(ObservableCollection<tblProject> table,
    ListSortDirection direction)
{
    ConfigureSorting(table, direction);
    foreach (tblProject project in table)
    {
        ConfigureSorting(project.tblLines, direction);
        foreach (tblLine line in project.tblLines)
        {
            //...etc...
        }
    }
}

但这不是该行的结尾。由于您可以将接口应用于生成的(如果是数据库或模型优先)或自写的(如果是代码优先)POCO,您可以创建一个允许递归配置对象的接口:

interface ICascadingSetup
{
   IEnumerable<object> Children { get; }
}

您可以将此接口应用于所有具有允许设置的子项的 POCO(即所有 除了 TblSubSubDevice):

partial class TblProject : ICascadingSetup
{
    IEnumerable<object> ICascadingSetup.Children => tblLines;
}

//...etc...

现在你可以引入一个递归方法来进行初始化:

public static void OrderTreeSetup(ObservableCollection<tblProject> table,
    ListSortDirection direction)
{
    ConfigureSortingRecursive(table, direction);
    //...all further initializations you need to do...
}

private static void ConfigureSortingRecursive(IEnumerable<object> entities,
    ListSortDirection direction)
{
    ICollectionView view = CollectionViewSource.GetDefaultView(entities);
    view.SortDescriptions.Clear();
    view.SortDescriptions.Add(new SortDescription("Name", direction));
    foreach (object entity in entities) {
        if (entity is ICascadingSetup cascadingSetup) {
            ConfigureSortingRecursive(cascadingSetup.Children, direction);
        }
    }
}

每当你有类似对象的这种树状表示时,总是值得检查递归是否是简化事情的一种选择。