【问题标题】:How to put values from database to object properly in C#如何在 C# 中将值从数据库正确放入对象
【发布时间】:2018-04-23 05:50:40
【问题描述】:

我在数据库中有一个具有这样结构的表;

ID | Process_Id | Attribute   | Parent_Id | Sequence
----------------------------------------------------
1     1          INDIVIDUAL     
2     1          FIRST_NAME         1         1 //parent_id is same as ID of its parent
3     1          SECOND_NAME        1         2
4     1          INDIVIDUAL_ALIAS   1   
5     1          ALIAS_NAME         4         1
6     2          sdnEntry       
7     2          firstName          6         1
8     2          lastName           6         2
9     2          aka                6   
10    2          firstName          9         1
11    2          lastName           9         2
12    1          ENTITY     
13    1          FIRST_NAME        12         1
14    1          ENTITY_ALIAS      12   
15    1          ALIAS_NAME        14         1

我为这些数据设置值的类如下所示;

将我之前的代码更新为DataAdapter 公共类属性 { 公共 int ProcessId { 获取;放; } 公共列表父节点 { 获取;放; }
}

public class ParentAttribute
{        
    public int id { get; set; } 
    public string parentNodeValue { get; set; }
    public List<ChildAttribute> ChildNodeValues { get; set; }
}

public class ChildAttribute
{
    public int sequence { get; set; }
    public string childNodeValue { get; set; }
    public int parentId { get; set; }
    //public List<GrandChildAttribute> childNodeValue { get; set; }
}

public class GrandChildAttribute
{
    public int sequence { get; set; }
    public string grandChildNodeValue { get; set; }
    public int parentId { get; set; }
}

这是我尝试在对象中放置值的方式,更新代码

public static Attribute GetProcessAttributes()
    {
        using (OracleConnection oCon = new OracleConnection(Con))
        {
            Attribute att = new Attribute();

            string query = @"SELECT * from Process where Process_Id = :Process_Id";                
            OracleCommand cmd = new OracleCommand(query, oCon);
            cmd.Parameters.AddWithValue("Process_Id", 1);
            oCon.Open();
             OracleDataReader rdr = cmd.ExecuteReader();
            DataTable dt = new DataTable();
            dt.Load(rdr);

            if (dt.Rows.Count > 0)
            {

                foreach (DataRow row in dt.Rows)
                {
                    att.ProcessId = Convert.ToInt32(row["Process_Id"]);

                    att.ParentNodes = new List<ParentAttribute>();
                    var pNodes = (from pRow in dt.AsEnumerable()
                                  where pRow.Field<decimal?>("Parent_Id") == null
                                  select pRow).ToList();

                    foreach (var pItem in pNodes)
                    {
                        ParentAttribute pAtt = new ParentAttribute();
                        pAtt.parentNodeValue = pItem["Attribute"].ToString();
                        pAtt.id = Convert.ToInt32(pItem["ID"]);

                        pAtt.ChildNodeValues = new List<ChildAttribute>();

                        var cNodes = (from cRow in dt.AsEnumerable()
                                      where cRow.Field<decimal?>("Parent_Id") == pAtt.id
                                      select cRow).ToList();


                        foreach (var cItem in cNodes)
                        {
                           //how to handle when childnode has further childs
                            ChildAttribute cAtt = new ChildAttribute();
                            if(cItem["Sequence"] == DBNull.Value)
                            {
                                cItem["Sequence"] = 0; //was unable to pass null value to Integer type in ternanry so did this
                            }
                            if (cItem["Parent_Id"] == DBNull.Value)
                            {
                                cItem["Parent_Id"] = 0;
                            }
                            cAtt.childNodeValue = cItem["Attribute"].ToString();
                            cAtt.sequence = Convert.ToInt32(cItem["Sequence"]);
                            cAtt.parentId = Convert.ToInt32(cItem["Parent_Id"]);

                            pAtt.ChildNodeValues.Add(cAtt);
                        }
                        att.ParentNodes.Add(pAtt);
                    }                               
                }                   
            }
            return att;
        }

    }

现在我可以在我的对象中放置值,我将不胜感激,但问题是一些子节点有单个值,一些包含更多列表,我如何在运行时为该属性分配类型。 在我目前的情况下,两个父节点 "INDIVIDUAL""ENTITY" 每个父节点都有自己的子节点,由 parent_Id parent_Id 标识到 parentNodes 被视为 null 为空,进一步的孩子也有一些孙子节点。

【问题讨论】:

  • 您想通过输入Process_Id获取特定进程的所有父进程?
  • 父母和他们各自的孩子也
  • 所以你需要递归迭代它,你知道如何递归吗?
  • @Aria 我更新了问题

标签: c#


【解决方案1】:

我认为要获取基于进程 ID 的所有父级,您应该执行以下操作:

假设您在表格中提到的每一行都是一个进程,因此要让所有父进程执行以下操作:

string end = string.Empty; 
List<Attribute> attributes= new List<Attribute>();
int searchId = childId;
do
{
    var processes =//Select from your table where Id = proccess_Id
    foreach (Process ps in processes )
    {
        end = ps.ParentID.ToString();
        attributes.Add(ps);
        proccess_Id= ps.ParentID;
    }
} while (end != string.Empty);

注意:string.Empty 是层次关系的结尾!。

要获取 Process 的所有子项,您可以执行以下操作:

 void GetChild(IEnumerable<Process> data, int? parentId = null)
{
    var items = data.Where(d => d.Parent_Id == parentId).OrderBy(i => i.MenuOrder);
    if (items.Any())
    {
        foreach (var item in items)
        {
            //Each Item is your child 
            GetChild(data, item.ID);
        }
    }
}

但您可以join 表本身来查找每行的父级,例如:

SELECT child.Id, child.Name, parent.Id, parent.Name
    FROM Process AS child
    LEFT JOIN Process AS parent ON child.ParentId = parent.Id;

【讨论】:

  • 这个会映射到我的对象类
  • 其实不行,你应该随心所欲地改进它,这只是一个解决方案,会给你线索
【解决方案2】:

首先,您不需要多个类,因为它们都代表一个表。我宁愿有一个为我设置树的自引用类。该类可能如下所示:

    public class Process
    {
        public int Id
        {
            get; set;

        }

        public int ProcessId
        {
            get; set;
        }

        public int Sequence
        {
            get; set;
        }

        public List<Process> Children
        {
            get; set;
        }

    }

这将保存所有记录,无论它们在树中的位置如何。现在要解析记录,我假设您在阅读器中获取数据的方式与表格中显示的方式相同。另外,不用改成table。

我尝试编写一个非常快速而肮脏的代码来遍历树以查找节点。只要深度不是很多并且记录数相当少,您就可以遍历列表以获取正确的父级。

    static void Main(string[] args)
    {
        List<Process> processes = new List<Process>();
        OracleDataReader reader = null;

        int? parentId = null;
        Process currentProcess = null;

        // Assumes that query results are ordered in a way that parent records appear before the child records
        while (reader.Read())
        {
            // Get the parent id from reader. Change index as per your need
            if (!reader.IsDBNull(1) && ((parentId = reader.GetInt32(1)) != null))
            {
                currentProcess = GetProcessRecord(processes, parentId);

                // add values to children to current process here
            }
        }

    }

    private static Process GetProcessRecord(List<Process> processes, int? parentId)
    {
        Process currentProcess = null;
        // This record has a parent. See if we already have it.
        if (processes.Any(x => x.Id == parentId))
        {
            // Found the parent record at level 0
            currentProcess = processes.First(x => x.Id == parentId);
            if (currentProcess.Children == null)
            {
                currentProcess.Children = new List<Process>();
            }
        }
        else
        {
            // Might be a child record of another parent
            foreach (var process in processes)
            {
                if (process.Children != null)
                {
                    currentProcess = GetProcessRecord(process.Children, parentId);
                    if (currentProcess != null)
                    {
                        return currentProcess;
                    }
                }
            }
        }

        return currentProcess;
    }

正如我之前提到的,这既快又脏,因此您可能需要优化代码以及可能还需要优化遍历的方法。如果适合您的需要,您可能还想利用并行执行。

要测试递归是否有效,可以使用以下代码:

        /* 
         * Set up the tree
         *       1
         *       |-4
         *       | |--10
         *       | |--11
         *       |-5
         *       2
         *       |-6
         *       |-7
         *       3
         *       |-8
         *       |-9
         */
        processes.Add(new Process { Id = 1, Children = new List<Process> { new Process { Id = 4, Children = new List<Process> { new Process { Id = 10 }, new Process { Id = 11 } } }, new Process { Id = 5 } } });
        processes.Add(new Process { Id = 2, Children = new List<Process> { new Process { Id = 6 }, new Process { Id = 7 } } });
        processes.Add(new Process { Id = 3, Children = new List<Process> { new Process { Id = 8 }, new Process { Id = 9 } } });
        var test = GetProcessRecord(processes, 11); // Test for various values

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 2018-09-27
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 2011-12-09
    • 2015-07-25
    相关资源
    最近更新 更多