2012-03-28 4 views
0

私はtbStudentsの学生を基本的に受け取り、tbTermsに最新の用語(数字ですが、文字列として格納されます)を取得するSQLクエリ(下記)を持っています。SQL - > LINQ(C#)

tbStudentsの学生とtbTermsの用語レコードの間に1対多の関係があります。例:

tbStudents:

StudentId FirstName LastName 
12345  John  Smith 
12346  Jane  Doe 

tbTerms:理想の

StudentId Term 
12345  1234 
12345  1235 
12345  1236 
12346  1233 
12346  1234 

StudentId FirstName LastName Term 
12345  John  Smith 1236 
12346  Jane  Doe  1234 

SQLクエリ:

select tbStudents.student_id, tbStudents.user_id, tbStudents.firstname, tbStudents.lastname, v.rTerm 
    from tbStudents 
    inner join (
     select tbTerms.student_id, MAX(tbTerms.term) as rTerm 
     from tbTerms 
     group by tbTerms.student_id 
    ) v on v.student_id = tbStudents.student_id 

私はこれをすべて1つのLINQ文にしようとしていますが、問題があります。 1つの声明でこれを行うためにとにかくありますか?複数のステートメントで実行する必要があります。ありがとうございました。

編集:私が試したことのC#コード。

var students = (from s in dockDb.tbStudents 
       join t in dockDb.tbTerms on s.student_id equals t.student_id 
       into pairs 
       from p in pairs 
       select new { UserId = s.user_id, StudentId = s.student_id, Term = p.term }).ToList(); 

出力は次のようになります。

StudentId FirstName LastName Term 
12345  John  Smith 1234 
12345  John  Smith 1235 
12345  John  Smith 1236 
12346  Jane  Doe  1233 
12346  Jane  Doe  1234 

編集#2:私は、データのためのEntity Frameworkのを使用しています。私はこれが何かに影響を与えるかどうかはわかりませんが、私が試してみると、ほとんどの解決策は「構文上正しくありません」です。より読みやすく書くのが自然であることを拡張メソッドを持つ

from s in dockDb.tbStudents 
join t in dockDb.tbTerms on t.student_id equals s.student_id into st 
group st by New {StudentID = st.student_id, Term = t.term} into g 
select New { g.Key, g.Max(i => i.Term) } 
+2

あなたが既に持っているかを示すことはできますか? –

+0

"構文的に正しくありません"。拡張機能AsEnumerable()を呼び出します。そして、それらは "統語的に間違った"ものではありません。 – OmegaMan

答えて

0

する必要があります。これを試してみてください:

from s in Students 
join t in Terms on t.StudentId = s.StudentId 
select new {Student = s, Term = t} 
group by s into g 
select new {g.Key.StudentId, g.Key.FirstName, g.Key.LastName, g.Max(x=>x.Term.term)}; 

最初の2行は、検索するドメインを定義しています。つまり、StudentIdによってリンクされた、学生と利用規約の内部結合された組み合わせです。 StudentとTermのそれぞれのユニークな組み合わせは、匿名型に入れられます。その後、これらのインスタンスは、それぞれ固有のStudentによってLookup(キーで参照されるIEnumerableの読み取り専用コレクション)にグループ化されます。キーの(生徒の)重要な情報を選択し、用語のリストで、最も価値の高いもの(最新のもの)を探します。

+0

コードを実行するためにコード内のいくつかの部分を修正する必要がありましたが、それ以外の場合は構造がかなり必要でした。ありがとう! – Mike

1

は、あなたはそのような何かを試してみてください。だから、ここに:

context.Students.Select(s => new 
{ 
    s.StudentId, 
    s.FirstName, 
    s.LastName, 
    Term = context.Terms.Where(t => t.StudentId == s.StudentId) 
         .Select(t => t.TermNumber) 
         .OrderByDescending(t => t) 
         .First() 
}); 

を基本的には、各学生のために、それはすべての彼/彼女の観点から、最新の少なくともへの最近の受注、それらを選択し、結果の最初の1(最新)が含まれています。

0

どういうわけか、私は常に考えられてきた構文:

0

Groupbyはあなたの友人です。学生IDでデータを単純にグループ化してから、プロジェクトを新しいフォームにグループ化します。これはlinqpadの例である:ここで

void Main() 
{ 
    var students = new List<Student>() 
    { 
     new Student() { StudentID = 12345, Name = "Smith" }, 
     new Student() { StudentID = 12346, Name = "Jones" } 
     }; 

    var terms = new List<Term>() 
    { 
     new Term() { StudentID=12345, TermID = 1234 }, 
     new Term() { StudentID=12345, TermID = 1235 }, 
     new Term() { StudentID=12345, TermID = 1236 }, 
     new Term() { StudentID=12345, TermID = 1237 }, 
     new Term() { StudentID=12346, TermID = 1233 }, 
     new Term() { StudentID=12346, TermID = 1234 }, 
    }; 

    var result = terms.GroupBy (tm => tm.StudentID) 
         .Select (gr => new 
    { 
     Name = students.First (s => s.StudentID == gr.Key).Name, 
     Terms = gr.Select (g => g.TermID) 
    }); 


    result.Dump(); 

} 

// Define other methods and classes here 
    public class Student 
    { 
     public int StudentID { get; set; } 
     public string Name { get; set; } 
    } 

    public class Term 
    { 
     public int StudentID { get; set; } 
     public int TermID { get; set; } 
    } 

を使用することができます出力されます。

enter image description here