Avatar billede Driton Seniormester
07. november 2015 - 15:49 Der er 12 kommentarer og
2 løsninger

Repeater inde i en repeater

Jeg har et problem med en til mange relation tabel, ved at de ikke vises korrekt. Som man kan se i mit kode

<asp:Repeater ID="RepeaterLektioner" OnItemDataBound="Repeater_noter_ItemDataBound"  runat="server">
                    <ItemTemplate>
                        <div style="margin:auto; width:300px; height:auto;">
                      <%#Eval("Dato", "{0: dd. MMMM yyyy}") %> - <%#Eval("Titel") %><br />
                            <%#Eval("introtekst") %><br />
                            <asp:Repeater ID="Repeater_noter" runat="server">
                                <ItemTemplate>
                                    <%#Eval("notenavn") %><br /><br />
                                </ItemTemplate>
                            </asp:Repeater>
                            </div>
                  </ItemTemplate>               
                </asp:Repeater>

Så er Repeater_noter er inde i  RepeaterLektioner. Der er flere noter til en lektion. Men jeg kan ikke få de korrekte noter ud til den lektion enten får jeg kun den første note, som viser sig på alle lektioner eller den sidste. Jeg ved hellere ikke hvordan jeg skal tackle denne problemstilling.

min codebehind ser sådan her ud

protected void RepeaterLektion()
    {
        SqlConnection conn = new SqlConnection();
        conn.ConnectionString = ConfigurationManager.ConnectionStrings["masterConnectionString"].ToString();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = "SELECT * FROM KursusLektion WHERE VisLektion = 1 and FK_KursusId = " + Request.QueryString["kursusid"];
       
       
       
        conn.Open();
       
        SqlDataReader reader = cmd.ExecuteReader();



        Session["id"] = reader["LektionId"];
            RepeaterLektioner.DataSource = reader;
            RepeaterLektioner.DataBind();
           
             
        conn.Close();
     
    }

    protected void Repeater_noter_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        Repeater Repeater_noter = null;
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
        {
          Repeater_noter = e.Item.FindControl("Repeater_noter") as Repeater;

        }
        SqlConnection conn = new SqlConnection();
        conn.ConnectionString = ConfigurationManager.ConnectionStrings["masterConnectionString"].ToString();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = "select * from kursusnoter where FK_kursuslektion = " + Session["id"];
        conn.Open();
        Repeater_noter.DataSource = cmd.ExecuteReader();
        Repeater_noter.DataBind();
        conn.Close();
    }


Jeg har prøvet ved at hvergang, jeg henter noget fra den første repeater at der oprettes en session med den nuværende session. Men koden kører hele den første repeater igennem, og så den inderste repeater en gang
Avatar billede Driton Seniormester
07. november 2015 - 15:50 #1
Hvis der er en anden letter måde at gøre det på, står jeg også åben for det. Det er logikken der fejler og jeg kan ikke komme på et andet logik, er gået helt i baglås
Avatar billede arne_v Ekspert
07. november 2015 - 16:01 #2
Det plejer at vaere nemt hvis man har List<Parent> og Parent indeholder en List<Child>.

Jeg tro derfor at du skal decouple din SQL og UI lidt mere og foerst laese fra database op i dat struktur og saa vise denne data struktur.
Avatar billede Driton Seniormester
07. november 2015 - 16:28 #3
Er der et sted, hvor man kan se et perfekt eksempel på det?
Avatar billede softspot Forsker
07. november 2015 - 16:38 #4
Som Arne skriver, så definér en klasse til lektion og en til note. Lektion skal indeholde en liste af noter.

public class Lektion
{
    public int Id { get; set; }
    public string Titel { get; set; }
    public List<Note> Noter { get; set; }
}

public class Note
{
    public int Id { get; set; }
    public string Tekst { get; set; }
}


Erklær derefter en liste af lektioner, som du indlæser data i og derefter binder til din repeater:

List<Lektion> lektioner = IndlaesLektionerMedNoter();

rptLektioner.DataSource = lektioner;
rptLektioner.DataBind();


Metoden IndlaesLektionerMedNoter henter alle relevante lektioner med tilhørende noter og opbygger dermed listen med lektioner. Dette kan gøres på forskellige måder, men resultatet skal være en fuldt indlæst liste.

Din form skal så indeholde en repeater i dette format:

<asp:Repeater id="rptLektioner" runat="server">
    <ItemTemplate>
        <%# Eval("Titel") %><br>
        <asp:Repeater runat="server" DataSource=<%# Eval("Noter") %>>
            <ItemTemplate>
                <%# Eval("Tekst") %><br/>
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>


Du skal altså ikke længere bruge eventhandlers til OnDataItemBound, da det hele sker på een gang.
Avatar billede softspot Forsker
07. november 2015 - 17:11 #5
IndlaesLektionerMedNoter kunne f.eks. implementeres noget i stil med dette:

public List<Lektion> IndlaesLektionerMedNoter()
{
    var lektioner = new List<Lektion>();
    var sql = @"
        SELECT l.* , n.*
        FROM KursusLektion l
        INNER JOIN kursusnoter n
            ON n.kursuslektion = l.LektionId
        WHERE l.KursusId = @kursusId
        ORDER BY l.LektionId";

    var connStr =
        ConfigurationManager
            .ConnectionStrings["masterConnectionString"]
                .ConnectionString;

    using (var conn = new SqlConnection(connStr))
    {
        var cmd = new SqlCommand(sql);
        cmd.Connection = conn;
        cmd.Parameters.AddWithValue("@kursusId", HttpContext.Current.Request.QueryString["kursusid"]);
        var reader = cmd.ExecuteReader();
        var prevId = 0;
        Lektion lektion = null;
        while (reader.Read())
        {
            var id = Convert.ToInt32(reader["LektionId"]);
            if (prevId != id)
            {
                prevId = id;
                lektion = new Lektion();
                lektion.Id = id;
                lektion.Titel = Convert.ToString(reader["Titel"]);
                lektion.Noter = new List<Note>();
                lektioner.Add(lektion);
            }
            else
            {
                var note = new Note();
                note.Id = Convert.ToInt32(reader["NoteId"]);
                note.Tekst = Convert.ToString(reader["Tekst"]);
                lektion.Noter.Add(note);
            }
        }
    }

    return lektioner;
}


Beklager hvis det ikke helt spiller, det er længe siden jeg har arbejdet med ADO.NET. Dette kan sikker gøres meget mere fikst, men betragt dette som et grundlag du kan arbejde videre med.

Det der sker er, at alle lektioner og tilhørende noter til ét kursusid indlæses på én gang og derefter opbygges listen med lektioner og underordnede noter. Lektionerne sorteres efter id for at forberede resultatet til det næste der sker.

Det næste er, at hver række gennemløbes og hvis der er tale om en ny lektion, så oprettes en ny lektion og objektet gemmes indtil lektionen skifter. Sålænge det er samme lektion tilføjes der blot noter til den aktuelle lektion.

Når der ikke er flere resultater, lukkes forbindelsen til databasen og den genererede liste med lektioner returneres.

Det faktisk indhold af felter og navngivningen heraf i de involverede tabeller kan du nok selv rette til. Strukturen burde være på plads med dette...
Avatar billede softspot Forsker
07. november 2015 - 17:14 #6
Se lige bort fra HttpContext.Current i eksemplet. Det var bare for at jeg kunne få intellisence i min editor. I realiteten burde du nok sende kursusId ind til funktionen som en parameter i stedet, så koden ikke er afhængig af System.Web...
Avatar billede Driton Seniormester
08. november 2015 - 00:31 #7
Nu har lavet to klasser


public class Lektion
{
    public Lektion()
    {
       
    }

    public Lektion(int visLektion, DateTime Dato, string Titel, string introtekst, List<kursusnoter> noter)
    {

        this.visLektion = visLektion;
        this.Dato = Dato;
        this.Titel = Titel;
        this.introtekst = introtekst;
        this.noter = noter;

    }

    int visLektion { get; set; }
    DateTime Dato { get; set; }
    string Titel { get; set; }
    string introtekst { get; set; }
    List<kursusnoter> noter { get; set; }
 
}




public class kursusnoter
{
    public kursusnoter()
    {
        //
        // TODO: Add constructor logic here
        //
    }
    public kursusnoter(int FK_KursusLektion, string notenavn, string notelink)
    {
        this.FK_Kursuslektion = FK_Kursuslektion;
        this.notenavn = notenavn;
        this.notelink = notelink;
    }

    public int FK_Kursuslektion { get; set; }
    public string notenavn { get; set; }
    public string notelink { get; set; }
}



Jeg vil ikke have løsning til mit svar, men mere psudo kodning til logikken. Fordi jeg kan ikke forstå, hvad du - @softspot, hentyder til. Synes også eksemplet du giver er en smule uoverskueligt for mig.

Hvad er det næste trin for mig for at løse mit problemstilling nu?
Avatar billede Driton Seniormester
08. november 2015 - 00:31 #8
Forresten hvordan laver i de der tags, som viser noget som kode.
Avatar billede arne_v Ekspert
08. november 2015 - 02:13 #9
Du skal laese ind fra din database til den valgte data struktur.

Hvis du havde brugt ORM, saa havde det hele sket automatisk.

Med ADO.NET skal du kode lidt.

Logikken er:

query = SELECT lektion JOIN noter
while more rows
{
    if not same lektion as last row
    {
      add lektion
    }
    add note
}
Avatar billede Driton Seniormester
08. november 2015 - 02:29 #10
Nu spørg jeg dumt. Men hvad er ORM?
Avatar billede Driton Seniormester
08. november 2015 - 02:51 #11
Kan i ikke lide begge smide et svar herinde, så jeg kan fordele pointen til jer. Da begge svar hjælp med løsning
Avatar billede arne_v Ekspert
08. november 2015 - 03:00 #12
ORM = Object Relational Mapper

De to mest brugte ORM i .NET verdenen er EF (Entity Framework) og NHibernate
Avatar billede arne_v Ekspert
08. november 2015 - 03:00 #13
et svar
Avatar billede softspot Forsker
08. november 2015 - 08:50 #14
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester