LINQ中的双重过滤

时间:2014-04-08 03:29:22

标签: c# sql linq

我需要根据GroupID加入所有数据,这些GroupID由EmpNo拥有

public IEnumerable<EmployeeWithEmail> GetAllEmployeesWithEmail(int EmpNo)
{
    using (var context = new SQL_TA_SCOREBOARDEntities1())
    {
        return (from ea in context.View_SystemAdminMembers
                join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
                join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
                from subjoin in outer_join 

              //need code to join all data according to EmpNo's GroupIDs

                group new
                {
                    ea.EmpNo,
                    subjoin.Role,
                    vh.EmailAddress,
                    vh.LNameByFName,
                    ea.Active

                } by vh.LNameByFName into grp
                let item = grp.FirstOrDefault()
                orderby item.Role ascending
                select new EmployeeWithEmail
                {
                    EmpNum = item.EmpNo ?? 0,
                    Role = item.Role,
                    EmailAddress = item.EmailAddress,
                    LNameByFname = item.LNameByFName,
                    Active2 = item.Active ?? false

                }).ToList();

    }
}

我想我正在尝试过滤两次并加入常见数据,但实际上有两个过滤器,我不知道如何控制。

所以我的输出就像:

EmpNo --->  __  01 |  01 |  01 | 01

GroupID --->  __10 |  10 |  20 | 20

Data ---> _________Apple | Apple | Orange | Orange

我可以过滤EmpNo 01和GroupID 10,但如果EmpNo属于两个组怎么办? 很抱歉找不到合适的术语。

提前致谢。

2 个答案:

答案 0 :(得分:2)

我并没有真正关注你的要求。也许它可以被改写或给予更多背景或格式不同?

但我想我会提出一些可能有助于你到达目的地的建议。

1 - 函数名称表示此人将提供电子邮件并使用该电子邮件接收多个Employee对象。但它似乎接受员工ID并返回EmployeeWithEmail列表。考虑重命名函数以匹配它正在做的事情。另请考虑返回IEnumerable<Employee>IEnumerable<IEmployeeEmailView>

2 - 这个功能做得很多。 (并且需要花费几秒钟才能弄清楚它在做什么)。在这种情况下,我会从简单开始。不要进行分组或排序或任何事情。有一些函数返回结果:

from ea in context.View_SystemAdminMembers
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
from subjoin in outer_join 

IEnumerable<Employee>

之类的形式出现
public class Employee {
     public int Id { get; set; }
     public string Role { get; set; }
     public string EmailAddress { get; set; }
     public string Name { get; set; }
     public bool IsActive { get; set; }
}

从那里开始,事情就更容易处理了。您不必使用LINQ-to-SQL。你可以做......

IEnumerable<Employee> employees = <your renamed function>();
var employeesGroupedByName = employees.GroupBy(e => e.Name);

希望这会让事情变得更轻松。它并没有解决你的答案,但我认为这可能会使事情变得更简单/更容易。

如此完全写出来,可能是这样的:

public class EmployeeRepository {
    public IEnumerable<Employee> GetAll() {
        // This function won't compile. I don't know the syntax for this type of LINQ
        using (var context = new SQL_TA_SCOREBOARDEntities1()) {
            return (from ea in context.View_SystemAdminMembers
            join vh in context.View_HCM on (Int16)ea.EmpNo
            join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
        }
    }

    public IEnumerable<Employee> GetAllEmployeesWithEmployeeId(int employeeId) {
        return GetAll().Where(e => e.Id == employeeId).ToList();
    }

    public IEnumerable<Employee> SomeOtherFunctionThatDoesWhatYouWantToDoFromThisPost() {
        // You could also create a class that extends IEnumerable<Employee> to
        // encapsulate the logic so that the repository doesn't have a million functions
    }
}

这就是我为你所做的一切。如果问题说得好一点,我可以给出一个更完整的答案,但希望这能让你走上正轨。

答案 1 :(得分:2)

根据您的评论,您尝试生成的SQL应该是(我已略微简化)

SELECT EmployeeAccess.EmpNo, View_SystemAdminMembers.LNameByFName, View_SystemAdminMembers.GroupName,
        View_SystemAdminMembers.Role, View_SystemAdminMembers.Active, View_SystemAdminMembers.EmpNo, 
        View_SystemAdminMembers.RoleID 
FROM EmployeeAccess 
    INNER JOIN View_SystemAdminMembers ON EmployeeAccess.GroupID = View_SystemAdminMembers.GroupID 
WHERE (EmployeeAccess.EmpNo = '01')

这与您在问题中显示的内容完全不同:

from ea in context.View_SystemAdminMembers
     join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
     join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
     from subjoin in outer_join

所以我不确定我的答案是否会有所帮助,但是为了得到你指定的SQL,我想你会想做:

var query =
from ea in context.EmployeeAccess
join vsam in context.View_SystemAdminMembers on ea.GroupID equals vsam.GroupID
where ea.EmpNo == "01"
select new
{
    ea.EmpNo, vsam.LNameByFName, vsam.GroupName, vsam.Role, vsam.Active, vsam.EmpNo, vsam.RoleID
};

使用流畅的语法(不是查询语法),它看起来有点像:

var query =
    context.EmployeeAccess
    .Join(context.View_SystemAdminMembers, allEA => allEA.GroupID, allVSAM => allVSAM.GroupID, (ea, vsam) => new {ea, vsam})
    .Where(combined => combined.ea.EmpNo == "01")
    .Select(combined => combined.ea.EmpNo, combined.vsam.LNameByFName, combined.vsam.GroupName, combined.vsam.Role, combined.vsam.Active, combined.vsam.EmpNo, combined.vsam.RoleID);

(虽然我承认 - 我通常会回复整个实体 .Select(combined => combined.ea)或类似的东西,所以我不是100%肯定最后一行......)

请注意,在这两种情况下,“var query”都将是IQueryable,这意味着您仍需要添加ToList或等效内容才能获得结果。不过,在你这样做之前,你需要应用Tim Burkhart的答案来对其进行任何修改(如GroupBy或其他)。正如他所指出的那样,关于IQueryable的一个很酷的事情是,你不必在一个陈述中全部完成;您可以像我在上面定义的那样使用query,然后添加类似

的内容
query = query.Where(c => c.LNameByFName.Contains("A"))

或其他什么。

还有一个注意事项 - 您的返回值完全由View_SystemAdminMembers中的项目组成,但EmployeeAccess.EmpNo除外,但由于您要对其进行过滤,因此您应该已经知道它是什么。仅返回View_SystemAdminMember对象可能更容易,而不是创建新类型。这取决于你。