开发者

How to join multiple tables using LINQ-to-SQL?

I'm quite new to linq, so please bear with me.

I'm working on a asp.net webpage and I want to add a "search function" (textbox where user inputs name or surname or both or just parts of it and gets back all related information). I have two tables ("Person" and "Application") and I want to display some columns from Person (name and surname) and some from Application (score, position,...). I know how I could do it using sql, but I want to learn more about linq and thus I want to do it using linq.

For now I got two main ideas:

1.)

    var person = dataContext.GetTable<Person>();
    var application = dataContext.GetTable<Application>();
    var p1 = from p in Person
             where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
             select new {Id = p.Id, Name = p.Name, Surname = p.Surname}; //or maybe without this line

 //I don't know how to do the following properly
 var result = from a in Application
                 where a.FK_Application.Equals(index)  //just to get the "right" type of application
                 //this is not right, but I don't know how to do it better
                 join p1
          开发者_如何学编程       on p1.Id == a.FK_Person

2.) The other idea is just to go through "Application" and instead of "join p1 ..." to use

var result = from a in Application
             where a.FK_Application.Equals(index)  //just to get the "right" type of application
             join p from Person
             on p.Id == a.FK_Person
             where p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1])      

I think that first idea is better for queries without the first "where" condition, which I also intended to use. Regardless of what is better (faster), I still don't know how to do it using linq. Also in the end I wanted to display / select just some parts (columns) of the result (joined tables + filtering conditions).

I really want to know how to do such things using linq as I'll be dealing also with some similar problems with local data, where I can use only linq. Could somebody please explain me how to do it, I spent days trying to figure it out and searching on the Internet for answers.


var result = from a in dataContext.Applications
             join p in dataContext.Persons
             on p.Id equals a.FK_Person
             where (p.Name.Contains("blah") || p.Surname.Contains("foo")) && a.FK_Application == index
             select new { Id = p.Id, Name = p.Name, Surname = p.Surname, a.Score, a.Position };

Well as Odrahn pointed out, this will give you flat results, with possibly many rows for a single person, since a person could join on multiple applications that all have the same FK. Here's a way to search all the right people, and then add on the relevant application to the results:

var p1 = from p in dataContext.Persons
             where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
             select new {
                Id = p.Id, Name = p.Name, Surname = p.Surname,
                BestApplication = dataContext.Applications.FirstOrDefault(a => a.FK_Application == index /* && ????  */); 
         }; 

Sorry - it looks like this second query will result in a roundtrip per person, so it clearly won't be scalable. I assumed L2S would handle it better.


In order to answer this properly, I need to know if Application and Person are directly related (i.e. does Person have many Applications)? From reading your post, I'm assuming that they are because Application seems to have a foreign key to person.

If so, then you could create a custom PersonModel which will be populated by the fields you need from the different entities like this:

class PersonModel
{
    string Name { get; set; }
    string Surname { get; set; }
    List<int> Scores { get; set; }
    List<int> Positions { get; set; }
}

Then to populate it, you'd do the following:

// Select the correct person based on Name and Surname inputs
var person = dataContext.Persons.Where(p => p.Name.Contains("firstname") || p.Name.Contains("surname")).FirstOrDefault(); 
// Get the first person we find (note, there may be many - do you need to account for this?)

if (person != null)
{
    var scores = new List<int>();
    var positions = new List<int>();

    scores.AddRange(person.Applications.Select(i => i.Score);
    positions.AddRange(person.Applications.Select(i => i.Position);

    var personModel = new PersonModel
                          {
                              Name = person.Name,
                              Surname = person.Surname,
                              Scores = scores,
                              Positions = positions
                          };
}

Because of your relationship between Person and Application, where a person can have many applications, I've had to account for the possibility of there being many scores and positions (hence the List).

Also note that I've used lambda expressions instead of plain linqToSql for simple selecting so that you can visualise easily what's going on.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜