You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何打破GetOrCreate系列方法的递归循环?

解决Employee/Position/Division创建循环依赖问题

问题背景

创建Division时,若未找到对应Director会调用GetOrCreateEmployee创建员工;创建Employee必须关联Position;创建Position又必须依赖Division,三个GetOrCreate方法互相调用形成递归死循环,尝试过标记和方法重载未解决。

原始代码

static public Employee GetOrCreateEmployee()
{
    Console.WriteLine("Enter the full name of the teacher:");
    string employeeName = Console.ReadLine();
    Employee employee = DB.employees.FirstOrDefault(e => $"{e.Name} {e.Surname} {e.Patronymic}".ToLower() == employeeName.ToLower());
    if (employee == null)
    {
        Console.WriteLine("Enter the employee's name:");
        string name = Console.ReadLine();

        Console.WriteLine("Enter the employee's last name:");
        string surname = Console.ReadLine();

        Console.WriteLine("Enter the employee's middle name:");
        string patronymic = Console.ReadLine();

        Position position = GetOrCreatePosition();
        employee = new Employee(name, surname, patronymic, position);
        DB.employees.Add(employee);
    }
    return employee;
}

static public Position GetOrCreatePosition()
{
    Console.WriteLine("Enter the title of the position:");
    string jobTitleName = Console.ReadLine();

    Position position = DB.positions.FirstOrDefault(j => j.Title.ToLower() == jobTitleName.ToLower());
    if (position == null)
    {
        position = DB.positions.FirstOrDefault(j => j.Title.ToLower() == jobTitleName.ToLower());
    }

    Console.WriteLine("Enter the title of the position:");
    string name = Console.ReadLine();

    Console.WriteLine("Enter the salary of the position:");
    int.TryParse(Console.ReadLine(), out int salary);

    Console.WriteLine("Enter the name of the department:");
    string subdivisionName = Console.ReadLine();
    Division division = DB.divisions.FirstOrDefault(s => s.Name.ToLower() == subdivisionName.ToLower());
    if (division == null)
    {
        Console.WriteLine("The division was not found. Create it");
        GetOrCreateDivision();
    }
    division = DB.divisions.FirstOrDefault(s => s.Name.ToLower() == subdivisionName.ToLower());
    Position speciality = new Position(name, salary, division);
    DB.positions.Add(speciality);
    Console.WriteLine("The position has been successfully created.");

    return position;
}

static public void GetOrCreateDivision()
{
    Console.WriteLine("Enter the name of the department:");
    string name = Console.ReadLine();

    Console.WriteLine("Enter the last name, first name and patronymic of the director:");
    string directorFullName = Console.ReadLine();
    Employee director = DB.employees.FirstOrDefault(e => $"{e.Name} {e.Surname} {e.Patronymic}" == directorFullName);
    if (director == null)
    {
        Console.WriteLine("The director has not been found. Create it.");
        GetOrCreateEmployee();
        director = DB.employees.Last();
    }

    Console.WriteLine("Enter the name of the organization:");
    string organizationName = Console.ReadLine();
    Organisation organization = DB.organisations.FirstOrDefault(o => o.Name.ToLower() == organizationName.ToLower());
    if (organization == null)
    {
        Console.WriteLine("The organization was not found. Create it");
        GetOrCreateOrganization();
    }
    organization = DB.organisations.FirstOrDefault(o => o.Name.ToLower() == organizationName.ToLower());
    Division subdivision = new Division(name, director, organization);
    DB.divisions.Add(subdivision);
    Console.WriteLine("The division has been successfully created.");
}

解决方案

循环的核心是实体间的强制依赖导致创建顺序死锁,以下三种方案可解决问题:

方案1:拆分实体初始化流程,允许临时无依赖实体

修改实体类,添加仅包含基础字段的构造函数,先创建核心实体,后续补全关联关系:

  1. 给实体添加精简构造函数:
    // Employee允许先创建无职位的实例
    public Employee(string name, string surname, string patronymic)
    {
        Name = name;
        Surname = surname;
        Patronymic = patronymic;
    }
    
    // Position允许先创建无部门的实例
    public Position(string title, int salary)
    {
        Title = title;
        Salary = salary;
    }
    
    // Division允许先创建无负责人的实例
    public Division(string name, Organisation organization)
    {
        Name = name;
        Organisation = organization;
    }
    
  2. 调整GetOrCreate方法逻辑:
    • 创建Director时,先存入无Position的Employee
    • 创建Division时,关联已创建的Director
    • 创建Position时,关联已创建的Division
    • 最后统一给Director补全Position信息

方案2:给方法添加重载,跳过强制依赖

通过重载方法,允许在特定场景下跳过循环依赖的创建步骤:

  1. 修改GetOrCreateEmployee添加重载:
    static public Employee GetOrCreateEmployee(bool requirePosition = true)
    {
        Console.WriteLine("Enter the full name of the teacher:");
        string employeeName = Console.ReadLine();
        Employee employee = DB.employees.FirstOrDefault(e => $"{e.Name} {e.Surname} {e.Patronymic}".ToLower() == employeeName.ToLower());
        if (employee == null)
        {
            Console.WriteLine("Enter the employee's name:");
            string name = Console.ReadLine();
            Console.WriteLine("Enter the employee's last name:");
            string surname = Console.ReadLine();
            Console.WriteLine("Enter the employee's middle name:");
            string patronymic = Console.ReadLine();
    
            if (requirePosition)
            {
                Position position = GetOrCreatePosition();
                employee = new Employee(name, surname, patronymic, position);
            }
            else
            {
                // 创建无职位的Director,后续补充
                employee = new Employee(name, surname, patronymic);
            }
            DB.employees.Add(employee);
        }
        return employee;
    }
    
  2. 修改GetOrCreateDivision调用重载:
    static public void GetOrCreateDivision()
    {
        // ... 原有输入部门名称、组织的逻辑 ...
    
        if (director == null)
        {
            Console.WriteLine("The director has not been found. Create it.");
            // 创建无职位的Director,避免触发循环
            director = GetOrCreateEmployee(requirePosition: false);
        }
    
        // ... 创建Division的逻辑 ...
    
        // 后续补全Director的职位
        Console.WriteLine("Do you want to set a position for the director? (Y/N)");
        if (Console.ReadLine().Trim().ToLower() == "y")
        {
            Position directorPosition = GetOrCreatePosition();
            director.Position = directorPosition;
            // 根据你的DB实现更新Employee记录
        }
    }
    

方案3:重构业务依赖,从根源打破循环

重新梳理业务逻辑,解除不必要的强制依赖:

  • 允许员工入职时暂不分配职位,后续再设置
  • 允许部门先创建,后续再指定负责人
    从业务规则层面移除循环依赖的强制要求,彻底避免死循环。

代码冗余修正

注意GetOrCreatePosition中有重复无效的查询代码,需删除:

// 这段代码完全冗余,删除
if (position == null)
{
    position = DB.positions.FirstOrDefault(j => j.Title.ToLower() == jobTitleName.ToLower());
}

内容的提问来源于stack exchange,提问作者Versst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:47:11