使用Linq执行左外连接时获取不正确的结果 - 为什么?

时间:2012-02-18 02:37:26

标签: c# linq left-join

我有以下

public class Person
    { 
        // Properties
        public string Name { get; set; }
        public string Area { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }

        public List<Person> GetPersonData()
        {
            List<Person> personLst = new List<Person>  {
           new Person { Name="Shashidhar Niketani", Age=20, Gender="Male" , Area = "Assam"},
           new Person { Name="Ahmed Ali Khan", Age=25 ,Gender="Male", Area = "Assam" },
           new Person { Name="S. Mirja", Age=20, Gender="Female", Area = "Assam"},
           new Person { Name="Neru Kumar", Age=18, Gender="Female", Area = "Colombo"},
           new Person { Name="Chidam P", Age=19, Gender="Male", Area = "Colombo"},
           new Person { Name="H Kontala", Age=19, Gender="Male", Area = "Bombay"},
           new Person { Name="Priya Pankhraj", Age=23, Gender="Female", Area = "North Punjab"},
             new Person { Name="Ambla", Age=20, Gender="Female", Area = "Madras"},
           new Person { Name="H Kontala", Age=25, Gender="Male", Area = "Bombay"},
           new Person { Name="Sirisha Chalukuri", Age=30, Gender="Female", Area = "Bombay"}};
            return personLst;
        }

        public override string ToString()
        {
            return string.Format("Patient Name: =  {0} , Age:= {1}, Gender:= {2}, Area: = {3}", Name, Age, Gender, Area);
        }

    }

    public class Hobbies
    {
        public string Owner { get; set; }
        public string HobbyName { get; set; }

        public List<Hobbies> GetHobbies()
        {
            List<Hobbies> hobbyList = new List<Hobbies>  {
           new Hobbies { Owner="Sirisha Chalukuri", HobbyName = "Singing"},
           new Hobbies { Owner="Priya Pankhraj", HobbyName = "Cooking" },
           new Hobbies { Owner="S. Mirja", HobbyName="Playing"},
           new Hobbies { Owner="Neru Kumar", HobbyName="Programing"}};
           return hobbyList;
        }
    }

我正在尝试执行左连接

//获取那些记录

Person p = new Person();
var personSource = p.GetPersonData();

Hobbies h = new Hobbies();
var hobbySource = h.GetHobbies();

//左外连接

var res8 = (from person in personSource                       
                        join hobby in hobbySource
                        on p.Name equals hobby.Owner into temp
                        from hobby in temp.DefaultIfEmpty()
                        select new
                            {
                                PersonName = p.Name,
                                PersonAge = p.Age,
                                Gender = p.Gender,
                                LivesIn = p.Area,
                                Hobby = (hobby == null) ? "N/A" : hobby.HobbyName
                            });

但是我无法得到正确的结果......所有记录都是以空/非匹配记录的形式出现的。至少有4条匹配的记录,其余的记录是不匹配的记录...

我更愿意给出这两个数据源,如果我们在PersonName和HobbyOwner上执行左连接,我们会期待的结果。

需要帮助

3 个答案:

答案 0 :(得分:1)

当您在选择投影中引用hobby.HobbyName时,如果一个人没有匹配的爱好,则爱好为空(对于空的爱好集合,DefaultIfEmpty返回null)。您需要检查业余爱好是否为空,如果是,则为选择投影中的Hobby属性指定一个默认值。例如:

select new
{
  PersonName = p.Name,
  PersonAge = p.Age,
  Gender = p.Gender,
  LivesIn = p.Area,
  Hobby = (hobby == null) ? "N/A" : hobby.HobbyName
});

此外,不知道这是不是一个拼写错误,但在你的查询中,你应该使用p时使用p:

var res8 = (from person in personSource                       
        join hobby in hobbySource
        on person.Name equals hobby.Owner into temp
        from hobby in temp.DefaultIfEmpty()
        select new
        {
         PersonName = person.Name,
         PersonAge = person.Age,
         Gender = person.Gender,
         LivesIn = person.Area,
         Hobby = (hobby == null) ? "N/A" : hobby.HobbyName
         });

答案 1 :(得分:0)

根据定义,左外连接将从第一个集合中获取所有记录,而不管右集合中是否存在匹配记录。

我认为你在寻找的是:

var res8 = (from person in personSource                       
                        join hobby in hobbySource
                        on p.Name equals hobby.Owner into temp
                        from hobby in temp.DefaultIfEmpty()
                        select new
                            {
                                PersonName = p.Name,
                                PersonAge = p.Age,
                                Gender = p.Gender,
                                LivesIn = p.Area,
                                Hobby = hobby == null ? null : hobby.HobbyName
                            });

答案 2 :(得分:0)

我需要对您的代码执行的唯一操作就是将最后一个块中的p更改为person(并且只删除我复制,修改后的最后一个块)并贴在下面):

var res8 = (from person in personSource
                    join hobby in hobbySource
                    on person.Name equals hobby.Owner into temp
                    from hobby in temp.DefaultIfEmpty()
                    select new {
                        PersonName = person.Name,
                        PersonAge = person.Age,
                        Gender = person.Gender,
                        LivesIn = person.Area,
                        Hobby = (hobby == null) ? "N/A" : hobby.HobbyName
                    });

另外,我不知道这段代码与你的实际代码有多相似,但你的GetPersonData()和GetHobbies()函数作为静态方法更有意义。这样你就不需要创建一个无用的Person或Hobbies实例来获取你的列表。看起来p Person实例让你离开了。