Om du inte vet vilka kolumner som du får tillbaka av din SQL sats, så har du nog ett konstigt designtänk någonstans.
Varför skulle du inte få tillbaka kolumnerner som du förväntar dig?
- M
9 svar · 348 visningar · startad av doggelito
finns det nått enkelt sätt att kolla om en sqldatareader innehåller en viss kolumn?
string foo = (string)dr["foo"];
om readern inte innehåller någon "foo" så slängs ju ett error.
jag skulle kunna kapsla in raden i en try, catch men det känns väldigt overkill.
jag kan ju också gå in i schematable och läsa metadatat om vilka kolumner som finns men det känns nästan ännu mer overkill!
jag skulle typ bara vilja kunna köra så här:
if (dr.IsColumn("foo"))
string foo = (string)dr["foo"];
men en sådan funktion finns så klart inte! :l eller? :D
/RED
Denna tyckte jag borde funka men det gör den inte!
if(dr["foo"] != null)
string foo = (string)dr["foo"];
Då får man: System.IndexOutOfRangeException
Om du inte vet vilka kolumner som du får tillbaka av din SQL sats, så har du nog ett konstigt designtänk någonstans.
Varför skulle du inte få tillbaka kolumnerner som du förväntar dig?
- M
Om man skapar upp en tabell dynamiskt så är det väl inte säkert att man vet vad kolumnerna heter i tabellen.
r: om så är fallet bör man ju ha namnen lagrade i vilket fall.. ;)
man kanske slumpgenererar fram tabellkolumner i realtid :D
En lösning:
if (dr.GetOrdinal("foo") > -1)
...
Gladh skrev:
Om du inte vet vilka kolumner som du får tillbaka av din SQL sats, så har du nog ett konstigt designtänk någonstans.
Mm, finns risk för det!
Hur "ska" man göra i detta scenario då?
Om man tänker sig menyer i x antal nivåer.
Jag har en SP som returnerar MenuID, ParentID, MenuName, Lft, Rgt, Lvl...
Lft, Rgt, och Lvl är kolumner som bestämmer nivån, (typ Joe Selko) och dessa skapas i SP:n (finns alltså inte fysiskt i tabellen).
Sen har jag en SP som hämtar en detaljsida på ett menyval, denna returnerar MenuID, ParentID, MenuName... och alltså inte Lft, Rgt och Lvl.
Hur gör jag då när jag binder datat till min menyklass?
Nu har jag en och samma metod med en sqldatareader som parameter och loopar denna.
Jag ser två alternativ:
1. Ändra detalj SP:n så den returnerar tomma Lft, Rgt och Lvl.
2. Använda två separata loopningar av repeatern.
Finns det andra sätt?
frequz skrev:
man kanske slumpgenererar fram tabellkolumner i realtid
Ja, det vore ju spännande! :)
doggelito skrev:
Jag har en SP som returnerar MenuID, ParentID, MenuName, Lft, Rgt, Lvl...
Lft, Rgt, och Lvl är kolumner som bestämmer nivån, (typ Joe Selko) och dessa skapas i SP:n (finns alltså inte fysiskt i tabellen).
Sen har jag en SP som hämtar en detaljsida på ett menyval, denna returnerar MenuID, ParentID, MenuName... och alltså inte Lft, Rgt och Lvl.
Du har alltså "2 olika" SP som du anropa med samma kod? Om det är fallet så splita upp de i 2 funktioner så har du löst ditt problem.
- M
Det ser ut så här: (jag är fortfarande rätt ny på det här så skäll inte för mycket på mitt tänk :D )
public Menus GetMenuByID(int menuID)
{
Menus menu = null;
DataManager dm = new DataManager();
SqlParameter[] param = {
dm.AddParam("@MenuID", SqlDbType.Int, menuID)
};
SqlDataReader dr = dm.GetReader("Menu_GetMenuByID", CommandType.StoredProcedure, param);
dr.Read();
if (dr.HasRows)
menu = Fill(dr);
if (dr != null)
dr.Dispose();
return menu;
}
public List<Menus> GetMenu()
{
DataManager dm = new DataManager();
SqlDataReader dr = dm.GetReader("Menu_GetMenu");
List<Menus> menus = new List<Menus>();
while (dr.Read())
{
menus.Add(Fill(dr));
}
if (dr != null)
dr.Dispose();
return menus;
}
Dessa båda fylls med hälp av metoden Fill:
public Menus Fill(SqlDataReader dr)
{
Menus menu = new Menus();
menu.MenuID = (int)dr["MenuID"];
menu.ParentID = (int)dr["ParentID"];
menu.MenuName = (string)dr["MenuName"];
menu.Lvl = (int)dr["Lvl"];
menu.Lft = (int)dr["Lft"];
menu.Rgt = (int)dr["Rgt"];
return menu;
}
Varför jag gjort en metod som fyller Menus var bara för att försöka vara lite objektorienterad och återanvända kod, helt enkelt!
Men jag kanske får ta och tänka om!? :l
Man skulle ju dock kunna göra som jag skrev ovan, att använda GetOrdinal, ex:
public Menus Fill(SqlDataReader dr)
{
Menus menu = new Menus();
menu.MenuID = (int)dr["MenuID"];
menu.ParentID = (int)dr["ParentID"];
menu.MenuName = (string)dr["MenuName"];
if(dr.GetOrdinal("Lvl") >-1)
menu.Lvl = (int)dr["Lvl"];
if(dr.GetOrdinal("Lft") >-1)
menu.Lft = (int)dr["Lft"];
if(dr.GetOrdinal("Rgt") >-1)
menu.Rgt = (int)dr["Rgt"];
return menu;
}
Men ni anser att det är helt knasigt, eller?
doggelito skrev:
Men ni anser att det är helt knasigt, eller?
Inte helt, men så hade inte jag gjort. Om du fortfarande vil använda samma metod för att fylla båda så hade jag gjort följande.
1. Sett till så att båda SP returnerar samma mängd kolumner, de kolumner som du inte behöver kan ju returnera 0, eftersom int-variablen kommer få det värdet i vilket fall som helst.
eller
2. skickat med en boolean/enumeration som hade berättat om jag velat fylla objektet med data från kolumnerne eller inte.
Ettan är att föredra, medans tvåan är en något bättre lösningen än den som du har nu, men inte mycket... ;)
- M
Gladh skrev:
Ettan är att föredra, medans tvåan är en något bättre lösningen än den som du har nu, men inte mycket... ;)
Hehe, då måste jag bara säga: -Tack! :bire
Gladh skrev:
Inte helt, men så hade inte jag gjort.
Hade du fyllt dem separat, direkt i GetMenuByID och GetMenu? Eller finns annan Super Gladh-lösning? :)
doggelito skrev:
Hade du fyllt dem separat, direkt i GetMenuByID och GetMenu? Eller finns annan Super Gladh-lösning?
Tja super och super, jag hade använt mig av en ORMapper som hade löst problemet åt mig ;)
- M