简体   繁体   中英

How to Avoid Recreating Object When Using Let with LINQ

Here is my data:

private List<Department> Data
{
    get
    {
        return new List<Department>
        {
            new Department{
                Id = 1, 
                Name = "Tech",
                Employees = new List<Employee>{
                    new Employee{Name = "x", Id = 1 },
                    new Employee{ Name = "y", Id = 2}
                }
            },
            new Department{
                Id = 2,
                Name = "Sales",
                Employees = new List<Employee>{
                    new Employee{Name = "a", Id = 3},
                    new Employee {Name = "b", Id = 4}
                }
            }
        };
    }
}

and here I am getting a list of all employees with their appropriate departments:

List<Employee> employees = (from department in Departments
                       let d = department
                       from e in d.Employees
                       select new Employee{
                            Id = e.Id,
                            Name = e.Name
                            Department = d
                       }).ToList();

What is bothering me is that I have to recreate my Employee object in order to attach the appropriate department to it. Is there a way that I could write my LINQ statement where I don't have to recreate the Employee?

There might be a better way to phrase this question-- so feel free to let me know is there is.

Edit The reason I'm going down this path is that I'm storing my data by serializing my department:

[
    {
        "Id":1,
        "Name":"Sales",
        "Employees":[{"Id":2,"Name":"x"},{"Id":1,"Name":"y"}]
    },
    {
        "Id":2,
        "Name":"Tech",
        "Employees":[{"Id":3,"Name":"d"},{"Id":4,"Name":"f"}]
    }

]

You should not have this problem in the first place - You should fully construct your Employee instances when you initially create them, not sometime later - if an employee needs a department to be used, you should add a constructor that allows/enforces providing it:

public Employee(int id, string name, Department department)
{
   ...
}

You could, if you really, really want, use a let -clause for a side-effect, since assignment expressions return a value:

List<Employee> employees = (from department in Departments
                            from e in department.Employees
                            let _ = e.Department = department
                            select e).ToList();

Also I fully agree with BrokenGlass ...

It looks like you want to use LINQ to update an instance. This is not the intended use. Use LINQ to query the instances you want to have, and then loop over the results to update. (non-nested) Loops are not evil.

var query = 
  from d in Departments
  from e in d.Employees
  select new { Employee = e, Department = d };

foreach(var x in query)
{
  x.Employee.Department = x.Department;
}

Using let is redundant and not useful in your example query.

Besides, LINQ is not the right tool here . You want to affect the state of the objects you're querying (ie creating side-effects), which is generally not recommended.

By direct comparison, this is a better alternative to what you're trying do to:

 foreach(var department in Departments)
 foreach(var employee in department.Employees)
     employee.Department = department;

If you can however, you should do the department assignment at the time you add the employees to the department, either in an AddEmployee method in the Department class, or maybe in a Employee.Department property setter .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM