webForumDet fria alternativet

gästbok med paging

15 svar · 823 visningar · startad av icaaq

icaaqMedlem sedan okt. 20005 273 inlägg
#1

Hur skulle ni gjort en gästbok med paging?

Jag sitter och kollar igenom de olika alternativen och jag tror att det smidigaste är en repeater med en hemmasnickrad pagingmodul....

men jag vill gärna ha lite synpunkter på hur ni har/skulle göra

Mvh icaaq

icaaqMedlem sedan okt. 20005 273 inlägg
#2

Web-Tor gav mig denna http://www.sitepoint.com/article/921/1
den gav mig mcket bra info.... tack för den Web-Tor :bire

Vill nån annan ge mig mer info är det bara att posta vidare...

Mvh icaaq

PatrikBMedlem sedan mars 20002 836 inlägg
#3

Klart användbar, den tackar vi för.

En av mina första asp.net apps var denna: http://www.mrwize.nu/corallrevets/guestbook/index.aspx och då vart det en egen hemma-snickrad paging mot en repeater.

Ska nog kika igenom den koden och bygga om mot tipset ovan :e

cya,
PatrikB

icaaqMedlem sedan okt. 20005 273 inlägg
#4

JAg tänkte använda mig av koden som fanns i artikeln men jag vet inte vilket sätt jag ska föra över datan från mitt datalayer till datalisten...... vad är att föredra en array eller ??

Mvh icaaq

PatrikBMedlem sedan mars 20002 836 inlägg
#5

Själv hämtar jag alla data i stort sett med DataReaders som jag sedan loopar igenom.
I varje loop initierar jag ett nytt object med data från databasen och sedan lägger jag till det objectet till en ObjectCollection som oftast har ärvt egenskaper av ArrayList eller HashTable ... eller implementerar IList etc. som sedan returneras istället för DataSets etc.

Även om DataSets är "best practice" enligt MS så använder sig den "klassen" oxå av DataReaders i botten för att populera sig.

Kika in Jimmy Nilssons artiklar om DataContainers på https://www.informit.com

cya,
PatrikB

icaaqMedlem sedan okt. 20005 273 inlägg
#6

Har du lite kod att visa PatrikB??

mvh icaaq

PatrikBMedlem sedan mars 20002 836 inlägg
#7
'## -- i BisDataAccessLayer --

Public Function GetClientList() As ClientCollection
	Dim Query As String
	Dim _clientList As New ClientCollection()

	Query = "SELECT * FROM Clients ORDER BY Client_Name ASC"

	Dim _dr As SqlDataReader = MyNamespace.MyWrapper.GetDataReader(Query)

	While _dr.Read()
		Dim _client As New ClientInfo()

			_client.ClientID = _dr("Client_ClientID")
			_client.Name = _dr("Client_Name")

		_clientList.Add(_client)
	End While

	Return _clientList
End Function

'## -- i BisLayer --
Public Class ClientCollection
	Inherits ArrayList
	Public Sub New()
	End Sub
End Class

Public Class ClientInfo

	Private m_clientID As Integer
	Private m_clientName As String

	Public Property ClientID() As Integer
		Get
			Return m_clientID
		End Get
		Set(ByVal Value As Integer)
			m_clientID = Value
		End Set
	End Property

	Public Property Name() As String
		Get
			Return m_clientName
		End Get
		Set(ByVal Value As String)
			m_clientName = Value
		End Set
	End Property

	Public Sub New()
	End Sub

	Public Function ListClients() As ClientCollection
		Dim _bdal As New BisDataAccessLayer()
			Return _bdal.GetClientList()
	End Function
End Class

Sedan där du ska accessa, sätta datasource och binda data:

Dim _clientInfo As New ClientInfo()
Dim _pds As New PagedDataSource()
	_pds.DataSource = _clientInfo.ListClients
	_pds.BindData()

ett litet exempel, och kan säkert göras bättre ;) .... funkar bra för mig :e

editerat:

Man kan ju slå ihop BisDataAccessLayer.GetClientList med BisLayer.ListClients .... dvs endast ha: Design / BisLayer / Database

/editerat

cya,
PatrikB

icaaqMedlem sedan okt. 20005 273 inlägg
#8

Är en ArrayList flerdimensionell?

PatrikBMedlem sedan mars 20002 836 inlägg
#9

Vad menar du med "flerdimensionell"?

Jag ser en ArrayList som en lite mer avancerad array.
Kika i SDK'n och jämför de olika egenskaperna för Array klassen och ArrayList klassen

cya,
PatrikB

icaaqMedlem sedan okt. 20005 273 inlägg
#10

SDK skrev:

An Array can have multiple dimensions, while an ArrayList always has exactly one dimension.

Vad jag tänker på är att kan jag lägga flera värden i samma post? För i varje loop som DataReadern gör så har jag ju namn, epost, url och medelande som jag vill lägga till i samma post. Om ni förstår vad jag menar.....

Mvh icaaq

DinoMedlem sedan sep. 20011 914 inlägg
#11

Han lägger in värdena i en class som han sen lägger till arraylisten alias classen ClientCollection. Och på så sätt får han in flera värden i en post i arraylisten.

icaaqMedlem sedan okt. 20005 273 inlägg
#12

Det har du rätt i ..... ska kolla lite närmare på det :)

Mvh icaaq

PatrikBMedlem sedan mars 20002 836 inlägg
#13

Jepp,
det är ju det jag gör .... indirekt så att säga.

I varje loop initierar jag ett nytt objekt med olika egenskaper (metoder). Det är det objektet som man sedan lägger till i arraylisten så att varje index i arrayen är ett bis-objekt så att säga med alla dess egenskaper och metoder intakta :e

cya,
PatrikB

GladhMedlem sedan maj 20012 812 inlägg
#14

Egna klasser och kollection mot datasets är en debatterad fråga och jag med många med mig (inkls PatrikB) föredra klasser. Det finns många fördelar (och vissa nackdelar) och just paging och arraylist är riktigt enkelt eftersom du kan ta ut den delmängd från din arraylist.

Du säger på vilken post den skall starta och hur många poster som skall ut. Och vips så har du fått en paging method. Du kan även i arraylisten sortera dina poster. Så arraylisten utgör en hyfsat bra grund för en collectionklass, det finns tillfällen då HashTable är bättre.

En sak som inte tagits upp här är möjligheten med .NET Reflextion att skapa en DataManager klass som har en funktion som heter LoadData(object oObject) som oberoende av vilken klass du skickar in fyller ditt object med data. Det kräver dock att du skapar egna Attributs och läser på om Reflextions, men när du väl har gjort den så behöver du aldrig mer skriva kod för att fylla dina objekt med data. Du sätter bara Attributs på din variabler i de olika klasserna. Otroligt smidigt. Tycker verkligen det är nog som man skall lära sig då man slipper skriva en massa kod när man väl fått sin DataManager att fungera som man vill.

- M

PatrikBMedlem sedan mars 20002 836 inlägg
#15

Gladh skrev:

En sak som inte tagits upp här är möjligheten med .NET Reflextion att skapa en DataManager klass som har en funktion som heter LoadData(object oObject) som oberoende av vilken klass du skickar in fyller ditt object med data. Det kräver dock att du skapar egna Attributs och läser på om Reflextions, men när du väl har gjort den så behöver du aldrig mer skriva kod för att fylla dina objekt med data. Du sätter bara Attributs på din variabler i de olika klasserna. Otroligt smidigt. Tycker verkligen det är nog som man skall lära sig då man slipper skriva en massa kod när man väl fått sin DataManager att fungera som man vill.

- M

Det skulle jag vilja läsa lite mer om. Vart hittar man mer info om detta?
Har försökt åstadkomma liknande, och även skapa åtkomst av data oberoende av dbms.
Just att fylla alla object med data typ - LoadData(Value As Object) - skulle underlätta en hel del.

Kan du visa lite kod?

cya,
PatrikB

cya,
PatrikB

GladhMedlem sedan maj 20012 812 inlägg
#16

Visst skulle jag kunna det det är dock en hel del. Du behöver en del Attribute klasser och sedan en DataManager och sedan en DataAccess. Du behöver också en BaseCollection-class.

Oberoendet från DBMS kan lösas med hjälp av Interfacen istället för SqlDataReader/OleDbReader kan man använda sig av IDataReader. Professional ADO.NET från wrox har ett kapitel om hur de löser en DataAccess klass som är oberoende av DBMS.

Här kommer lite kod hur du kan lösa det med en LoadData() funktion i en DataManager. Nu visar jag endast hur du kan fylla ett singel objekt med en StoreProcedur.

Attribute för StoreProcedure namnet:

using System;

namespace Test
{
	/// <summary>
	/// Summary description for SqlParameterLoadAttribute.
	/// </summary>
	[AttributeUsage(AttributeTargets.Field)]
	public class StoreProcedureAttribute : Attribute
	{
		#region public methods ---------------------------------------------------------------------------------
			public StoreProcedureAttribute(){}
		#endregion
	}
}

Attribute för databasfältet:

using System;

namespace Test
{
	/// <summary>
	/// Summary description for SqlParameterLoadAttribute.
	/// </summary>
	[AttributeUsage(AttributeTargets.Field)]
	public class DatabasFieldAttribute : Attribute
	{
		#region variables --------------------------------------------------------------------------------------
			private string m_DatabasFieldName;
		#endregion

		#region property ---------------------------------------------------------------------------------------
			public string FieldName{
				get{return m_DatabasFieldName;}
			}
		#endregion

		#region public methods ---------------------------------------------------------------------------------
			public DatabasFieldAttribute(string sDatabasFieldName){
				m_DatabasFieldName = sDatabasFieldName;
			}
		#endregion
	}
}

Sedan kod för ditt objekt där du sätter attributen StoreProcedure och Databasfield på members:

using System;
using System.Data.SqlTypes;

namespace Test
{
	/// <summary>
	/// Summary description for COrder.
	/// </summary>
	public class COrder : BaseClass
	{
		#region variables --------------------------------------------------------------------------------------
			[StoreProcedure()]
			private string m_StoreProcedureName 
			
			[DatabasField("UsedFromTurn")]
			private int m_UsedFromTurn;

			[DatabasField("OrderName")]
			private string m_OrderName;
		#endregion

		#region property ---------------------------------------------------------------------------------------

			public int UsedFromTurn{
				get{return m_UsedFromTurn;}
				set{m_UsedFromTurn = value;}
			}
			public string OrderName{
				get{return m_OrderName;}
				set{m_OrderName = value;}
			}
		#endregion

		#region constructors -----------------------------------------------------------------------------------
			private COrder(){}

			public COrder(string storeProcedureName){
				m_StoreProcedureName = storeProcedureName;
			}
		#endregion
	}
}

Och sedan sist DataManger klassen, här har jag plockat bort en del kod eftersom vårt exempel inte använder sig av all kod som jag har i min klass. Det finns dock methoder för att skapa SqlParameters, läsa SqlParameters, spara data...

using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Reflection;

namespace Test
{
	/// <summary>
	/// Summary description for DataManager.
	/// </summary>
	public sealed class DataManager
	{
		#region constructors -----------------------------------------------------------------------------------
			private DataManager(){}
		#endregion

		#region private methods	--------------------------------------------------------------------------------
			private static void BindDataToObject(object oObject, SqlDataReader oDataReader){
				//-- get all fields for this object
				foreach (FieldInfo fieldInfo in oObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.Default))
				{
					//-- check every field if they have a Attribute named 'DatabasFieldAttribute' and set the value to this field
					if(Attribute.IsDefined(fieldInfo, typeof(DatabasFieldAttribute), true))
					{
						string sFieldName = ((DatabasFieldAttribute)fieldInfo.GetCustomAttributes(typeof(DatabasFieldAttribute),false)[0]).FieldName;
						fieldInfo.SetValue(oObject, oDataReader[sFieldName]);
					}
				}
			}

			private static string GetStoreProcedureName(object oObject){
				//-- get all fields for this object
				foreach (FieldInfo fieldInfo in oObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.Default)){
					//-- check every field if they have a Attribute named 'StoreProcedureAttributes'.
					if(Attribute.IsDefined(fieldInfo, typeof(StoreProcedureAttribute), true))
						return fieldInfo.GetValue(oObject).ToString();
				}
				throw new Exception("Can't find any field with information about StoreProcedureName");
			}
		#endregion

		#region public methods ---------------------------------------------------------------------------------
			public static void LoadData(object oObject){
				//-- declare variables
				SqlDataReader oDataReader = null;
				string sStoreProcedureName = GetStoreProcedureName(oObject);
				SqlCommand oSqlCommand = new SqlCommand();

				//-- init commandobject
				oSqlCommand.CommandType = CommandType.StoredProcedure;
				oSqlCommand.CommandText = sStoreProcedureName;

				//-- create parameters for this object
				CreateSqlParameters(oSqlCommand, oObject, StoreProcedureAction.Load);

				try{
					//-- Read data from databas	
					oDataReader = DataAccess.DataAccess.ExecuteReader(oSqlCommand);

					//-- bind data to object
					while(oDataReader.Read())
						BindDataToObject(oObject, oDataReader);
				}
				catch(Exception exception){
					throw new Exception("Error", exception);
				}finally{
					//-- close reader
					if(oDataReader != null)
					oDataReader.Close();
				}
			}

			public static void LoadData(BaseCollection oObject){
				//-- declare variables
				Type tItemType = ((ItemObjectTypeAttribute) oObject.GetType().GetCustomAttributes(typeof(ItemObjectTypeAttribute),true)[0]).Type;
				string sStoreProcedureName = GetStoreProcedureName(oObject);

				SqlDataReader oDataReader = null;
				SqlCommand oSqlCommand = new SqlCommand();

				//-- init commandobject
				oSqlCommand.CommandType = CommandType.StoredProcedure;
				oSqlCommand.CommandText = sStoreProcedureName;

				//-- create parameters for this object
				CreateSqlParameters(oSqlCommand, oObject, StoreProcedureAction.Load);			

				try{
					//-- Read data from databas	
					oDataReader = DataAccess.DataAccess.ExecuteReader(oSqlCommand);

					while(oDataReader.Read()){
						object tmpObject = Activator.CreateInstance(tItemType, true);
						BindDataToObject(tmpObject, oDataReader);
						oObject.Add(tmpObject);
					}
				}catch(Exception exception){
					throw new Exception("Error", exception);
				}finally{
					//-- close reader
					if(oDataReader != null)
						oDataReader.Close();
				}
			}

		#endregion
	}
}

Det fungerar så här. Först skapar man sig egna Attributeklasser som du sätter på dina fält/funktioner/klasser. Dessa Attribute definerar om ett fält skall fyllas med värde från databasen och vad fältet i databasen heter: [DatabasField("ID")]

Samma fungerar för Attributet StoreProcedure, fast här har jag valt att man kan skicka in detta från mitt affärslager så jag kan kalla på olika SP om jag vill detta. Man kan lika gärna skriva in Namnet på SP som man gör med Databasfältet, men då kan man endast ha en SP till sin klass.

Sedan i objektet så definerar man sina fält och sätter de Attribute på fältet som man vill ha, du kan ha många Attribute på ett fält, ibland samma Attribute (måste dock skapas med AllowMultiple = True).

Sedan kommer vi till DataManager. Här finns nu LoadData(object oObject) vilket fyller ett objekt, och LoadData(BaseCollection oObject) som fyller ett CollectionObject.

I LoadData så börjar jag med att hämta Namnet på SP och jag vet att jag skall leta efter ett fält som har Attributet [StoreProcedureNamn] och när jag har hittat det fältet (loopar igenom alla fält för klassen) så hämtar jag värdet i det fältet med GetValue().

Sedan så skapar jag en massa Parameters (vilket inte visas här) sedan hämtar jag en DataReader från min DataAccess-klass som har hand om alla DataAccess. Detta DataReader object använder jag när jag sedan skall fylla mitt objekt med data.

I DataBindToObject() så loopar jag igenom alla fält som klassen har och kollar om de har attributet [DatabasField()] definerad, om det har det, så hämtar jag ut värdet från dataReadern och sätter detta till mitt fält med SetValue().

Det är en start, läs på om Attributes och testa dig fram med funktionen GetType() som finns till alla objekt, så hittar du massor med smått och gott.

- M

135 ms totalt · 3 externa anrop · v20260731065814-full.c2d75422
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
133 ms — hämta tråd, inlägg och bilagor (db)