الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

تعرف على Objectdatasource و انسى قيود ال Sqldatasource

بدأه Slayer666 في 12 سبتمبر 2008 · 20 رد · 4,204 مشاهدة · في ASP.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ان اكتب اول موضوع لي و هذا الموضوع للمحترفين فقط او شبه المحترفين اما المبتدئين فا اعتذر هذا الموضوع ليس لكم

عملت على الموضوع اكثر من 7 ساعات :( فا اي خطا تجدوه فهو هفوة و ان كانت هناك طرق افضل من التي استخدمتها فلا تبخل علينا :wink:

80 بالمية من مبرمجين يستخدمون SqlDataSoure لسهولتها و قوة ادائها مع ال DataBinding و لكن لديها العديد من المشاكل

هل مللت من حدودها و تريد التحرر من قيودها و شروطها؟

هل تود ان تعمل كلاس بحيث يعمل على السي شارب و الفيجول بيسك و ايضا مع ال ASP .net ولكن كيف ستضيفه الى ال ASP .net؟

هل مللت صعوبة التعديل على SqlDataSoure و مشاكلها؟

موضوعي هذا سوف يحررك من شروطها و ينتقل بك الى عالم جديد من الداتا سورس عالم غير منتهي و ليس لديه اي قيود او حدود -_-

لعمل كل هذا اقد لكم طريقة عمل ObjectDataSource و كيف ربطه مع الدتا كرد و الدتيل فيو

لتكملة هذا الموضوع يجب ان يكون لديك خلفية للDataBainding و كيفة انشاء كلاس :blink:

في البداية اعمل تيبل في قواعد بياناتك فيه اربع اعمدة استخدمت هنا قواعد بيانات من نوع MySQL للتغير ;) فقط يمكن العمل على اي نوع انت تفضله :happy:

CREATE TABLE arabteam.users (
   userID INT(11) UNSIGNED AUTO_INCREMENT NOT NULL,
   Name VARCHAR(50) NOT NULL,
   Country VARCHAR(40),
   Age TINYINT(4) UNSIGNED,
  PRIMARY KEY (userID)
);

البروسيجرات

البروسيجر الاول اسمة GetUsersDetailes يقوم هذا البروسيجر بارجاع جميع الصفوف من قواعد البيانات

DROP PROCEDURE IF EXISTS arabteam.GetUsersDetailes;
CREATE PROCEDURE arabteam.`GetUsersDetailes`()
BEGIN
SELECT userID, Name, Country, Age 
FROM arabteam.users;
END;

البروسيجر الثاني GetUserDetailes يقوم باعدة صف واحد من قواعد البيانات بعد ارسال ال userID له

DROP PROCEDURE IF EXISTS arabteam.GetUserDetailes;
CREATE PROCEDURE arabteam.`GetUserDetailes`(in UserID INTEGER)
BEGIN
SELECT userID, Name, Country, Age 
FROM arabteam.users Where users.userID = UserID;
END;

البروسيجر الثالث يقوم بضافة يوزر جديد و ارجاع ال userID

DROP PROCEDURE IF EXISTS arabteam.AddNewUser;
CREATE PROCEDURE arabteam.`AddNewUser`(OUT userID INTEGER, IN Name Varchar(50), IN Country VARCHAR(40), IN age INTEGER)
BEGIN
INSERT INTO arabteam.users
(Name, Country, Age) 
VALUES (Name, Country, Age);
set userID := LAST_INSERT_ID();
END;

البروسيجر الرابع يقوم بتحديث الصف حسب الرقم التسلسلي

DROP PROCEDURE IF EXISTS arabteam.UpdateUser;
CREATE PROCEDURE arabteam.`UpdateUser`(IN UserID INTEGER,IN name Varchar(50), IN country VARCHAR(40), IN age INTEGER)
BEGIN
UPDATE arabteam.users 
SET Users.Name = name , Users.Country = country, Users.Age = age 
WHERE Users.userID = UserID;
END;

الخامس يقوم بخذف اليوزر

DROP PROCEDURE IF EXISTS arabteam.DeleteUser;
CREATE PROCEDURE arabteam.`DeleteUser`(IN UserID  INTEGER)
BEGIN
DELETE FROM Users WHERE ID = UserID;
END;

الان نذهب الى web.config و نضيف ال ConnectionString الخاص بقوعد البيانات

  <connectionStrings>
	<add name="MySqlConnectionString"  providerName="MySql.Data.MySqlClient"  
		 connectionString="server=localhost;user id=root;password=YourPassword;persist security info=True;database=arabteam;Character Set=UTF8"/>
  </connectionStrings>

الان ندخل في صلب الموضوع للعمل على هذا الموضوع يجب تكون كلاسين الاول يحتوي على بروبتيز سوف نستخدمها لخزن المعلومات المستخدم

public class UserDetails
{
	public UserDetails()
	{
	}

	public UserDetails(int userID, string name, string country, int age)
	{
		this.userID = userID;
		this.name = name;
		this.country = country;
		this.age = age;
	}

	private int userID;
	public int UserID
	{
		get { return userID; }
		set { userID = value; }
	}

	private string name;
	public string Name
	{
		get { return name; }
		set { name = value; }
	}

	private string country;
	public string Country
	{
		get { return country; }
		set { country = value; }
	}   

	private int age;
	public int Age
	{
		get { return age; }
		set { age = value; }

	}
}

الكلاس الثاني يحتوي على عدد من المثيودز كل مثود له وضيفة خاصة مع قواعد البيانات لم اقوم بشرحها لانها خارج الموضوع

using System;
using System.Collections.Generic;
using System.Data;
using System.Web.Configuration;
using MySql.Data.MySqlClient;

/// <summary>
/// Summary description for UserDB
/// </summary>
public class UserDB
{
	private string connectionString;
	public UserDB()
	{
		connectionString = WebConfigurationManager.ConnectionStrings["MySqlConnectionString"].ConnectionString;
	}

	public UserDB(string connectionString)
	{
		// استخدام كونكشن خاص
		this.connectionString = connectionString;
	}

	public int InsertUser(UserDetails user)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("AddNewUser", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?Name", MySqlDbType.VarChar, 50));
		cmd.Parameters["?Name"].Value = user.Name;

		cmd.Parameters.Add(new MySqlParameter("?Country", MySqlDbType.VarChar, 40));
		cmd.Parameters["?Country"].Value = user.Country;

		cmd.Parameters.Add(new MySqlParameter("?age", MySqlDbType.Int16, 0));
		cmd.Parameters["?age"].Value = user.Age;

		cmd.Parameters.Add(new MySqlParameter("?UserID", MySqlDbType.Int32, 0));
		cmd.Parameters["?UserID"].Direction = ParameterDirection.Output;

		try
		{
			con.Open();
			cmd.ExecuteNonQuery();
			return (int)cmd.Parameters["?UserID"].Value;
		}
		catch (MySqlException)
		{
			throw new ApplicationException("خطا في  قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}


	public UserDetails GetUserDetailes(int userID)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("GetUserDetailes", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?userID", MySqlDbType.Int32, 0));
		cmd.Parameters["?userID"].Value = userID;

		try
		{
			con.Open();
			MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow);

			if (!reader.HasRows) return null;

			reader.Read();

			UserDetails user = new UserDetails(reader.GetInt32("userID"), reader.GetString("Name"), reader.GetString("Country"), reader.GetInt32("Age"));
			reader.Close();
			return user;
		}
		catch (MySqlException)
		{
			throw new ApplicationException("يوجد خطا في قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}


	public List<UserDetails> GetUsersDetailes()
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("GetUsersDetailes", con);
		cmd.CommandType = CommandType.StoredProcedure;


		List<UserDetails> users = new List<UserDetails>();

		try
		{
			con.Open();
			MySqlDataReader reader = cmd.ExecuteReader();
			if (!reader.HasRows)
				return null;
			while (reader.Read())
			{
				UserDetails user = new UserDetails(reader.GetInt32("userID"), reader.GetString("Name"), reader.GetString("Country"), reader.GetInt32("Age"));
				users.Add(user);
			}
			reader.Close();
			return users;
		}


		catch (MySqlException)
		{
			throw new ApplicationException("يوجد خطا في قواعد البيانات");
		}

		catch (Exception ex)
		{
			string r = ex.Message;
		}
		finally
		{
			con.Close();
		}
		return users;
	}

	public void DeleteUser(int userID)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("DeleteUser", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?UserID", MySqlDbType.Int32, 0));
		cmd.Parameters["?UserID"].Value = userID;
		try
		{
			con.Open();
			cmd.ExecuteNonQuery();
		}
		catch (MySqlException)
		{
			throw new ApplicationException("خطا في  قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}
	public void UpdateUser(int userID, string name, string country, int age)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("UpdateUser", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?userID", MySqlDbType.Int32, 0));
		cmd.Parameters["?userID"].Value = userID;

		cmd.Parameters.Add(new MySqlParameter("?name", MySqlDbType.VarChar, 50));
		cmd.Parameters["?name"].Value = name;

		cmd.Parameters.Add(new MySqlParameter("?country", MySqlDbType.VarChar, 40));
		cmd.Parameters["?country"].Value = country;

		cmd.Parameters.Add(new MySqlParameter("?age", MySqlDbType.Int32, 0));
		cmd.Parameters["?age"].Value = age;

		try
		{
			con.Open();
			cmd.ExecuteNonQuery();
		}
		catch (MySqlException ex)
		{
			string ms = ex.Message;
			throw new ApplicationException("خطا في  قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}


	public void UpdateUser(UserDetails theUser)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("UpdateUser", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?userID", MySqlDbType.Int32, 0));
		cmd.Parameters["?userID"].Value = theUser.UserID;

		cmd.Parameters.Add(new MySqlParameter("?name", MySqlDbType.VarChar, 50));
		cmd.Parameters["?name"].Value = theUser.Name;

		cmd.Parameters.Add(new MySqlParameter("?country", MySqlDbType.VarChar, 40));
		cmd.Parameters["?country"].Value = theUser.Country;

		cmd.Parameters.Add(new MySqlParameter("?age", MySqlDbType.Int32, 0));
		cmd.Parameters["?age"].Value = theUser.Age;

		try
		{
			con.Open();
			cmd.ExecuteNonQuery();
		}
		catch (MySqlException ex)
		{
			string ms = ex.Message;
			throw new ApplicationException("خطا في  قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}


}

لحد الان لن ندخل للموضوع كل هذا هي اعدادات لبداية العمل الان لنفتح صفحة

ونضيف اليها كائن من نوع ObjectDataSource

و نكتب اسم الكلاس في TypeName و نكتب اسم الميثود في SelectMethod

		   <asp:ObjectDataSource ID="ODS0" runat="server" TypeName="UserDB" SelectMethod="GetUsersDetailes" />

post-59755-1221247490_thumb.jpg

ثم نضيف داتا كريد

			<asp:GridView ID="DG1" runat="server" DataSourceID="ODS0" />

الان الناتج

post-59755-1221247711_thumb.jpg

لحد الان الموضوع سهل

ماذا لو اردت تمرير براميتر؟؟ الى احد الميثود الموجودة؟

لنشاهد المثيود

public UserDetails GetUserDetailes(int userID)

يجب تمرير قيمة لل userID حتى نحصل على معلومات المستخدم

في البداية دعنا نقوم نعمل List تحتوي على جميع المستخدمين و عند اختيار احد المستخديم نقوم بعرض معلوماته كاملة

لنسخدم نفس الطريقة التي استخدمناها سابقا و نقوم بربط اللست مع "ODS0"

مع اضافة الخاصتين DataTextField و DataValueField

<asp:ListBox ID="ListBox1" runat="server" DataSourceID="ODS0" DataTextField="Name", DataValueField="UserID" />

الان لنذهب للمفيد هو كيفية اضافة باراميتر للداتا سورس اوبجكت و ربطه بالكونترل DropDownList

لنضيف ObjectDataSource ثاني

	   <asp:ObjectDataSource ID="ODS1" runat="server" TypeName="UserDB"
			 SelectMethod="GetUserDetailes">
			   <SelectParameters>
				   <asp:ControlParameter ControlID="ListBox1" Name="userID" PropertyName="SelectedValue" />
				</SelectParameters>
		 </asp:ObjectDataSource>

نشاهد هنا انه لقد قمت بضافة الباراميتر عن طريق ال ControlParameter

يمكن استخدام اي نوع من انواع البراميتر مثل التي في ال SqlDataSourse

كا

CookieParameter

او

QueryStringParameter

او استخدام البراميتر الاعتيادي

Parameter

كما تعرفون لانكم مبرمجون محترف او شبه محترفون ;)

الان نغير الداتا سور كرد فيو الى ال ODS1

<asp:GridView ID="DV1" runat="server" DataSourceID="ODS1" />

و لنفذ البرنامج

post-59755-1221247804_thumb.jpg

سنرى مشكلة هي عند تنفيذ البرنامج لاول مرة سوف يضع لنا اول اسم في القائمة ماذا لو كان المحتوى الاول هو "----الرجاء قم بختيار احد الاسماء----"؟؟

لحل هذا المشكلة يجب علينا كتابة بعد من الاكواد ولاول مرة

نذهب الى الايفينت Selecting الخاص ب ال ODS1

و نلغي العملية عند طريق تغير القيمة البولونية Cancel الى true

	protected void ODS1_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
	{
		if (e.InputParameters["userID"] == null)
			e.Cancel = true;
	}

الان الى تعديل البيانات و استخدام الميثود UpdateUser

لنتذكر تعريف الميثود

public void UpdateUser(int userID, string name, string country, int age)

يجب تمرير اربع براميترات الى الميثود لاكمال عملية الادخال

في البداية عدنا نعرف الميثود في الاوبجكت ObjectDataSource

باضافة البروبرتي UpdateMethod ولا تنسى تفعيل خاصية التعديل في الGridView

	   <asp:ObjectDataSource ID="ODS1" runat="server" TypeName="UserDB"
			 SelectMethod="GetUserDetailes" oninserting="ODS1_Inserting" UpdateMethod="UpdateUser">
			   <SelectParameters>
				   <asp:ControlParameter ControlID="ListBox1" Name="userID" PropertyName="SelectedValue" />
				</SelectParameters>
		 </asp:ObjectDataSource>

لقد مررنا اسم الميثود الخاص بالتحديث

"UpdateMethod="UpdateUser

الفيو كرد

		<asp:GridView ID="DV1" runat="server" DataSourceID="ODS1" >
		   <Columns>
			   <asp:CommandField ShowEditButton="True" />
		   </Columns>
		</asp:GridView>

الان نفذ البرنامج

post-59755-1221247882_thumb.jpg

لم انسى البراميترز و لكني لم اقم بضافتها لان الاوبجكت هو الذي قام بذالك عني

عندما يحصل الاوبجكت على المعلومات يقوم بضافة البراميترز حسب البروتبرتيز الاول اذن هو من قام بضافة

userID, Name , Country , Age

الان يخطر في بالك سؤال كيف استطاع التميز بينهما هناك نقطتان يعتمد عليها الاوبجكت

الاول عدد البراميترز المرسلة الى الميثود

الثانية يقوم بالتاكد من اسماء المتغيرات و مطابقتها اي بمعنى يجب عليك وضع نفس الاسماء الموجودة داخل الداتا سورس بمعنى نفس الاسماء التي يعديها الميثود الموجود داخل ال SelectMethod

و هي في موضوعنا هذا البروبرتيز الموجود في UserDetailes

ولكن لانك مبرمج محترف سوف تفضل عمل الميثود بهذه الصورة و هي الصورة الاكثر شيوعاً بين المبرمجين

	public void UpdateUser(UserDetails theUser)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("UpdateUser", con);
		cmd.CommandType = CommandType.StoredProcedure;

		cmd.Parameters.Add(new MySqlParameter("?userID", MySqlDbType.Int32, 0));
		cmd.Parameters["?userID"].Value = theUser.UserID;

		cmd.Parameters.Add(new MySqlParameter("?name", MySqlDbType.VarChar, 50));
		cmd.Parameters["?name"].Value = theUser.Name;

		cmd.Parameters.Add(new MySqlParameter("?country", MySqlDbType.VarChar, 40));
		cmd.Parameters["?country"].Value = theUser.Country;

		cmd.Parameters.Add(new MySqlParameter("?age", MySqlDbType.Int32, 0));
		cmd.Parameters["?age"].Value = theUser.Age;

		try
		{
			con.Open();
			cmd.ExecuteNonQuery();
		}
		catch (MySqlException ex)
		{
			string ms = ex.Message;
			throw new ApplicationException("خطا في  قواعد البيانات");
		}
		finally
		{
			con.Close();
		}
	}

انظر لعد تم استبدال البراميترز الاربعة بي براميتر واحد

اننا نواجه مشكلة :(( هل يوجد حل؟؟؟

بالطبع مايكروسوفت وضعت لك الحل و هي بتعريف ال UserDetailes

داخل الاوبجكت و بسطر واحد فقط ;)

اضف اسم الكلاس في البروبرتيز DataObjectTypeName="UserDetails"

	   <asp:ObjectDataSource ID="ODS1" runat="server" TypeName="UserDB"
			 SelectMethod="GetUserDetailes" UpdateMethod="UpdateUser" 
			onselecting="ODS1_Selecting" DataObjectTypeName="UserDetails">
			   <SelectParameters>
				   <asp:ControlParameter ControlID="ListBox1" Name="userID" PropertyName="SelectedValue" />
				</SelectParameters>
		 </asp:ObjectDataSource>

و الان جرب الكود لم يتغير شي يمنك الان حذف المثيود الاول لن تحتاج

الان الى المرحلة الاخيرة لنتذكر معا الميثود الخاص باضافة مستخدم جديد

public int InsertUser(UserDetails user)

نلاحظ هنا ان الميثود يقوم بارجاع ID المستخدم الجديد هل من الممكن الحصول على هذا القيمة؟؟؟ :wacko:

نعم من الممكن هذا

قم با ضافة Label لمساعدتنا على التاكد من ان الايدي صحيح

<asp:Label ID="Label1" runat="server" EnableViewState="false" />

و اقوم باضافة DetailsView مع تفعيل خاصية الاضافة لها

	   <asp:DetailsView ID="DV0" runat="server"
				DataSourceID="ODS1" AllowPaging="True">
			<Fields>
			   <asp:CommandField ShowEditButton="True" ShowInsertButton="True" />
			</Fields>
	   </asp:DetailsView>

الان يجب اضافة باراميتر الى الاوبجكت البراميتر حاله حال اي براميتر اخر و اضافة الايفنت OnInserted سوف نستخدمه لاحقاً

و اضافة ال InsertMethod

		 <asp:ObjectDataSource ID="ODS1" runat="server" TypeName="UserDB"
			 SelectMethod="GetUserDetailes" UpdateMethod="UpdateUser" InsertMethod="InsertUser" 
			onselecting="ODS1_Selecting" DataObjectTypeName="UserDetails" 
			oninserted="ODS1_Inserted">
			   <SelectParameters>
				   <asp:ControlParameter ControlID="ListBox1" Name="userID" PropertyName="SelectedValue" />
				</SelectParameters>
				<InsertParameters>
				   <asp:Parameter Direction="Output" Name="userID" Type="Int32" />
				</InsertParameters>
		 </asp:ObjectDataSource>

الان مين اين سوف نحصل على القيمة المرجوعة؟؟؟

بعد الانتهاء العملية سوف يطلق الObjectDataSource الايفنت oninserted

و تحت الاركمنت لهذا الايفنت يوجد الخاصة ReturnValue التي تحمل قيمة البرامتير الخارج ;)

	protected void ODS1_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
	{
		Label1.Text = "تم اضافة المستخدم :" + e.ReturnValue.ToString();
	}

post-59755-1221248018_thumb.jpg

post-59755-1221247972_thumb.jpg

اتمنى ان يكون الموضوع مفيد لكم و اي سؤال او استفسار انا حاضر -_-

ملف السورس كامل في المرفق الاخير :wub:

ArabTeamODS_Sur.zip

تم تعديل هذه المشاركة بواسطة slayer666 في 13 سبتمبر 2008 في 02:02

#2

شكرا أخي على الدرس

سبحان الله

اليوم كنت أطلع على مشروع جاهز من موقع مايكروسفت

وشوفت ObjectDataSource لكن بعدني ما تمرت عليها

اقتباس
80 بالمية من مبرمجين يستخدمون SqlDataSoure لسهولتها و قوة ادائها مع ال DataBinding و لكن لديها العديد من المشاكل

هل مللت من حدودها و تريد التحرر من قيودها و شروطها؟

هل تود ان تعمل كلاس بحيث يعمل على السي شارب و الفيجول بيسك و ايضا مع ال ASP .net ولكن كيف ستضيفه الى ال ASP .net؟

هل مللت صعوبة التعديل على SqlDataSoure و مشاكلها؟

لو من الممكن أن تخبرنا على أهم عيوبها على شكل نقاط

عندي سؤال خارج الموضوع أذا ممكن

ما الفرق بين هذا البراميتير والأخر

cmd.Parameters.Add(new MySqlParameter("?Country", MySqlDbType.VarChar, 40))

و

Parameters.AddWithValue

أعرف أنه في الأول تحدد نوع الداتا

قصدي من حيث الأداء و الأمن

و شكرا

تعلم فليس المرء يولد عالماً------ وليس أخو علماً كمن هو جاهلا

العلم نور وجمال يقتبس--------------- صاحبه مكرم اين ما جلس

من فاته العلم ساعة تظعظع ونتكس----شتان شتان بين حمار وفرس

#3
Al-Mohana كتب:
لو من الممكن أن تخبرنا على أهم عيوبها على شكل نقاط

لديها العديد من المشاكل

الاولى- ان كل كود SQL سيكود داخل الصفحة حتى لو كان Stoned Prosedure فيجب كاباتبه داخل الصفحة

الثانية- هي ان مهام ال SqlDataSource تكون محصورة داخل قواعد البيانات فقط ادراج تحديث حذف عرض ماذا لو كنت تريد ان تقوم بالمزيد؟ كرفع صورة مثلا؟ احتساب قيمة جديدة معينة

الثالثة - انها صعبة التعديل مثلا لديك نفس العمليات في صفحات مختلفة في كل صفحة يجب اعداد ال SqlDataSource مذا لو كان المشروع كبير؟؟؟

الرابعة - اذا كنت تملك الكلاس من برنامج قديم مثلا كنت تعمل على برنامج و طلبوا منك تحويله الى ال ASP .net

خامساً - قلة مرونتها مثلا لو انت تقوم باكثر من نوع من ال select استناد على نوع البراميتر الداخل يجب ان تضع لكل عملية SqlDataSourcr خاص بيها بالنهاية سوف يكون لديك صفحة يصعب تحليلها

سادسا - و هي العديد من الشركات تقوم بفصل المبرمجين الصفحات عن مبرمجين قواعد البيانات و تقوم فقط بعطائك الكلاس الخاص بيها

السؤال الثاني

يوجد فرق حيث الثاني لا يحدد النوع و اذا لم تقم بتحديد سوف يعتمد على الاسم فقط بدون النوع و هذا سوف يسبب بعض العموض لنوع البيانات

.net سوف يقوم بسناد النوع حسب القيمة المرسلة ولكن مذا لو كانت متشابهة و ليس هذا ما تريد؟ و هذا سوف يولد خطأ

#4

الف شكر يا اخ slayer

درس جامد وفى الجون

تسلم ايديك

ولدي إليك وصيتي عهد الأسودْ

العز غايتنا نعيش لكي نسود

و عريننا في الأرض معروف الحدود

فاحم العرين و صنه عن عبث القرود

أظفارنا للمجد قد خُلقت فدى

و نيوبنا سُنَّت بأجساد العدى

و زئيرنا في الأرض مرهوب الصدى

نعلي على جثث الأعادي السؤددا

#5

شكرا على الشرح وربنا ينور حياتك

الميثود GetUsersDetailes لو عبأت به Gridview هل استطيع عمل Paging ؟

هل يلزم الكلاس UserDetails اي اضافة لدعم Paging&Sorting ان لك تكن مدعومة

The World Must Be Crazy

#6

تسلم ايديك يا أخ slayer666 موضوع أكثر من رائع.....

وهذا الموضوع يدخل في صلب الN-Tier Applications حيث ان كل طبقة من المشروع منفصلة عن غيرها مما يعطي اعتمادية كبيرة للنظام و سهولة التعديل و الاضافة فيه .........بعكس اسلوب حشو كل عمليات النظام في الكونترول ايفينتس ......... موضوع احترافي فعلا

بارك الله فيك

#7
newbie كتب:
شكرا على الشرح وربنا ينور حياتك

الميثود GetUsersDetailes لو عبأت به Gridview هل استطيع عمل Paging ؟

هل يلزم الكلاس UserDetails اي اضافة لدعم Paging&Sorting ان لك تكن مدعومة

لا يلزم اي تعديل على الكلاس فقط اضف Paging و البقية سوف يقوم بيها الدوت نت

و شكرا جميعا على المرور :wub: و اتمنى استفدتم من الموضوع

#8

يعطيك العافية مجهود كبير

المزيد والمزيد حتى نستفيد من خبرتك

:)

موفق ان شاء الله

You can fly while you can touch the sky

#9

شكرا عزيزي على التوضيح ,,

كتبت على عجل في سؤالي الذي قصدت به التوضيح الذي جزيت عنه خيرا ,,, في الواقع كنت اقصد Sorting فقط وليس Paging لأن Generic Collections هذا الأمر متروك فيه للمبرمج على حسب معلوماتي البسيطة

The World Must Be Crazy

#10
محمد خليل أبو صلاح كتب:
يعطيك العافية مجهود كبير

المزيد والمزيد حتى نستفيد من خبرتك

:)

موفق ان شاء الله

نحن من بحاجة لخبرات خبرينا :wink:

وشكرا للمرور

#11
newbie كتب:
شكرا عزيزي على التوضيح ,,

كتبت على عجل في سؤالي الذي قصدت به التوضيح الذي جزيت عنه خيرا ,,, في الواقع كنت اقصد Sorting فقط وليس Paging لأن Generic Collections هذا الأمر متروك فيه للمبرمج على حسب معلوماتي البسيطة

هنا توجد مشكلة اذا كنت تحتاج الى Sorting فا الحل الافضل هو الاستعانة ب DataTable او DataSet

لان الObjectDataSource لا يدعم ال Sorting لل IEnumerable :(

#12

السلام عليكم

الله يعطيك الف عافيه على هذا الشرح

ممكن نطور المثال

اذا استخدمنا datalist واردنا ان نعمل paging كيف ممكن عملها

واذا اردنا استخدام cach كيف ممكن استخدامها

سلام

#13
madridi كتب:
السلام عليكم

الله يعطيك الف عافيه على هذا الشرح

ممكن نطور المثال

اذا استخدمنا datalist واردنا ان نعمل paging كيف ممكن عملها

واذا اردنا استخدام cach كيف ممكن استخدامها

سلام

لا تقلق بخصوص الكاش فال ObjectDataSource يقوم بذالك عنك :wink:

و بالنسبة DataList فانا شخصيا لا استعملها ولكن ان قمت بستخدام ListView فالامر بسيط فقط قم بتحديد PageSize

<LayoutTemplate>
<table id="groupPlaceholder" runat="server">
</table>
<asp:DataPager runat="server" ID="ContactsDataPager" PageSize="6">
#14
slayer666 كتب:
لا تقلق بخصوص الكاش فال ObjectDataSource يقوم بذالك عنك :wink: ]

ايش بتقصد اذا ممكن توضح اكثر يعني اذا الموقع بدخل عليه زوار بشكل كبير فالمفروض اني استخدم الكاش حتى مش كل مره اقوم بالاستعلام من الداتا بيز

كيف ممكن حلها

شكرا

#15
madridi كتب:
ايش بتقصد اذا ممكن توضح اكثر يعني اذا الموقع بدخل عليه زوار بشكل كبير فالمفروض اني استخدم الكاش حتى مش كل مره اقوم بالاستعلام من الداتا بيز

كيف ممكن حلها

شكرا

اخي العزيز ال ObjectDataSource مشتق من ال DataSourceControl

كما الحال مع SqlDataSource

عند طلب البيانات يقوم الاوبجكت بحفظ البيانات في الكاش و اذا تم التعديل على لبيانات سوف يقوم الابوجكت بحذفها من الكاش و اضافها مرة اخرى :wink:

يمكنك التاكد من هذا من خلال النظر الى قائمة الProperty و انظر الى CacheDuration="Infinite"

يمكنك التعديل عليها ان شئت

تم تعديل هذه المشاركة بواسطة slayer666 في 14 سبتمبر 2008 في 05:19

#16
اقتباس
هنا توجد مشكلة اذا كنت تحتاج الى Sorting فا الحل الافضل هو الاستعانة ب DataTable او DataSet

لان الObjectDataSource لا يدعم ال Sorting لل IEnumerable

كما قلت سابقا على المبرمج يضيف هذه الإمكانية بنفسه , وان كنت سأستخدم DataTable او DataSet فما الحاجة لإستخدام System.Collections.Generic من الاساس؟

عموما رأيت طرق كثيرة ,, الآن نحن بصدد عمل Sorting لـ GridView او ListView باستخدام ObjectDatasource أي ان الأمر تدخل فيه ك هذه الأشياء التي تتحدث عنها,

هذه احدى الطرق المعروفة :

لعمل Sort على GridView على سبيل المثال نضغط على العمود ولنفرض اننا ضغطنا على Age سيكون الإستعلام الذي نحصل عليه :

Age DESC او Age ASC او Age اي ColumnName +Direction

حتى لو كانت الكلاس UserDetails مجهزة بمعالج للـ Sorting فإنها لا تستطيع ان تفهم آلية الـ GridView

هناك طرق لعمل Sorting يمكنك ان تبحث عن Sorting System.Collections.Generic وستجد الكثير

اما الآن سنحاول هذه الطريقة

سنقوم بتغيير

public List<UserDetails> GetUsersDetailes()

الى

public List<UserDetails> GetUsersDetailes(string sortExpression)

اضافة

 GenericComparer<UserDetails> comparer = new GenericComparer<UserDetails>().OrderBy(sortExpression);
			users.Sort(comparer);
			return users;

لا حظ الكود مباشرة قبل return users;

وهذا هو الكلاس GenericComparer والذي يمكنك استخدامه في كامل المشروع

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
public class GenericComparer<T> : IComparer<T>
{
	Type declaringClassType = typeof(T);
	IList<PropertyOrderBy> properties = new List<PropertyOrderBy>();

	/// <summary>
	/// Default ctor instantiates a new GenericComparer instance. 
	/// </summary>
	public GenericComparer() { }

	public GenericComparer<T> OrderBy(string sqlOrderBy)
	{
		string[] parts = sqlOrderBy.Split(',');
		foreach (string part in parts)
		{
			string[] orderbyParts = part.Trim().Split(' ');
			string fieldName = orderbyParts[0].Trim();
			string direction = string.Empty;

			if (orderbyParts.Length > 1)
				direction = orderbyParts[1].Trim();

			properties.Add(new PropertyOrderBy(fieldName, direction));
		}

		return this;
	}

	private IComparable GetPropertyValue(object instance, string propertyName)
	{
		object val=null;
		// This won't work if the property is overloaded by type
		PropertyInfo info = declaringClassType.GetProperty(propertyName);
		if (info != null)
		{
			val = info.GetValue(instance, null);

			IComparable retVal = val as IComparable;

			if (retVal == null)
			{
				throw new ApplicationException(
				 propertyName +
				 " Type must implement IComparable to be able to use a PropertyComparer.");
			}

			return retVal;
		}
		else
		{
			return 0;
		}
	}

	#region IComparer<T> Members

	public int Compare(T OjectA, T ObjectB)
	{
		int result = 0;

		foreach (PropertyOrderBy orderBy in properties)
		{
			IComparable A = GetPropertyValue(OjectA, orderBy.PropertyName);
			IComparable B = GetPropertyValue(ObjectB, orderBy.PropertyName);

			if (orderBy.SortDirection == "DESC")
				result = B.CompareTo(A);
			else
				result = A.CompareTo(B);

			if (result != 0)
				return result;
		}

		return result;
	}

	#endregion

	private class PropertyOrderBy
	{
		public string PropertyName;
		public string SortDirection = "ASC";

		public PropertyOrderBy(string propertyName, string direction)
		{
			direction = direction.ToUpper();
			if (direction != "ASC" && direction != "DESC" && direction != string.Empty)
				throw new ArgumentOutOfRangeException("direction", "Unknown order by direction: " + direction + ", expected either ASC or DESC.");

			if (direction != string.Empty)
				this.SortDirection = direction;

			this.PropertyName = propertyName;
		}
	}
}

سنضيف حدث OnSorting للجريد فيو

protected void GriD_Users_Sorting(object sender, GridViewSortEventArgs e)
	{
		if (String.IsNullOrEmpty(e.SortExpression)) { return; }
		string direction = "";
		if (ViewState["SortDirection"] != null)
			direction = ViewState["SortDirection"].ToString();

		if (direction == "ASC")
		{
			direction = "DESC";
		}
		else
		{
			direction = "ASC";
		}
		ViewState["SortDirection"] = direction;
		string[] sortColumns = e.SortExpression.Split(',');
		string sortExpression = sortColumns[0] + " " + direction;
		for (int i = 1; i < sortColumns.Length; i++)
			sortExpression += ", " + sortColumns + " " + direction;
		e.SortExpression = sortExpression;
		   }

وايضا هنا لا يتأثر بعدد الحقول او اسمائها ويمكنك عمل كوبي بيست ومهمة الكود تهيئة الإستعلام SortExpression

عند الضغط على عمود فإنه يغير الـ Sort Direction

اخيرا تمرير SortExpression من خلال ObjectDataSource

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"  SortParameterName="sortexpression"
		SelectMethod="GetUsersDetailes" TypeName="UserDB">
		</asp:ObjectDataSource>

بقى ان تجعل AllowSorting="True"

The World Must Be Crazy

#17

عندما كنت انت تكتب هذا الرد الرائع بل اكثر من رائع كنت انا اطور الموضوع

ولكن انت قمت بعمل رائع صحيح لم اقم بتجريبه لحد الان ولكن الفكرة رائعة

و بما اني قمت بكتابة موضوع كامت و اخذ الكثير من الوقت سوف اقوم بضافة الى الرد

هناك طريقة لتفعيل الترتيب(الSorting) مع ال ObjectDataSource

الطريقة تعتماد على ال DataSet او ال DataTable عند الاتصال مع قواعد البيانات ثم ترتيبها و بعد ذالك اضافتها الى الكائن(Object)

في البداية يجب اضافة SortParameterName الى ObjectDataSource و هذا المتغير سوف يحمل المعلومات على العامود الذي تم النقر عليه

 SortParameterName="sortColumn"

يصبح ال ObjectDataSource كما ياتي

	   <asp:ObjectDataSource ID="ODS0" runat="server" TypeName="UserDB" SortParameterName="sortColumn" 
			SelectMethod="GetUsersDetailes" DataObjectTypeName="UserDetails"
			DeleteMethod="DeleteUser" InsertMethod="InsertUser" UpdateMethod="UpdateUser">
		   <DeleteParameters>
			   <asp:Parameter Name="userID" Type="Int32" />
		   </DeleteParameters>
		</asp:ObjectDataSource>

الان يجب التعديل الميثود على الGetUsersDetailes الخاص بجلب جميع المستخدمين من قاعدة البيانات

و التعديل هو

سحب البيانات عن طريق ال DataAdapter و وضعها في DataSet يمكن استخدام ال DataTable هنا و لكني قمت بستخدام ال DataSet في هذا المثال فقط للتوضيح

	public List<UserDetails> GetUsersDetailes(string sortColumn)
	{
		MySqlConnection con = new MySqlConnection(connectionString);
		MySqlCommand cmd = new MySqlCommand("arabteam.GetUsersDetailes", con);
		cmd.CommandType = CommandType.StoredProcedure;
		MySqlDataAdapter adp = new MySqlDataAdapter(cmd);

		DataSet ds = new DataSet();
		try
		{
			adp.Fill(ds, "users");
		}
		catch (MySqlException ex)
		{
			throw new ApplicationException("هناك خطا في الاتصال بقواعد البيانات");
		}
		catch (Exception ex)
		{
			string ms = ex.Message;
		}

		//هنا سوف نقوم بعمل السورتنك
		//في البداية نقوم عمل DataView 
		DataView dv = ds.Tables[0].DefaultView;
		//هنا نقوم بالعملية
		dv.Sort = sortColumn;

		List<UserDetails> users = new List<UserDetails>();
		foreach (DataRowView row in dv)
		{
			try
			{
				int userid = Convert.ToInt32(row[0]);
				string name = (string)row[1];
				string country = (string)row[2];
				int age = (int)Convert.ToInt32(row[3]);
				UserDetails user = new UserDetails(userid, name, country, age);
				users.Add(user);
			}
			catch (Exception ex)
			{
				string ms = ex.Message;
			}

		}
		return users;
	}

التغير بسيط جدا كل ما قمت باضافته هو انني قمت بوضع البيانات في DataSet

		MySqlDataAdapter adp = new MySqlDataAdapter(cmd);

		DataSet ds = new DataSet();
		try
		{
			adp.Fill(ds, "users");
		}
		catch (MySqlException ex)
		{
			throw new ApplicationException("هناك خطا في الاتصال بقواعد البيانات");
		}

هنا قمت بعملية الترتيب (Sort) بستخدام القيمة الممرة sortColumn

		DataView dv = ds.Tables[0].DefaultView;

		dv.Sort = sortColumn;

ثم قمت هنا بعمل Loop لوضع القيمة الموجود داخل الDataView في الList

		foreach (DataRowView row in dv)
		{
			try
			{
				int userid = Convert.ToInt32(row[0]);
				string name = (string)row[1];
				string country = (string)row[2];
				int age = (int)Convert.ToInt32(row[3]);
				UserDetails user = new UserDetails(userid, name, country, age);
				users.Add(user);
			}
			catch (Exception ex)
			{
				string ms = ex.Message;
			}

		}

ملاحظة مهمة جدا استخدمت الFunction Convert.ToInt32 بدل من المعامل (int) بسبب ان خطا في ال MySQL Connector \ Net 5.2.3

		 int userid = Convert.ToInt32(row[0]);

الان قم بتفعيل الٍSorting في ال ViewGrid و ضع القيمة ترو AllowSorting="True"

<asp:GridView ID="GV0" runat="server" DataSourceID="ODS0" AllowSorting="True"
			AutoGenerateColumns="False" SelectedRowStyle-BackColor="Brown" >
		   <Columns>
			   <asp:CommandField ShowSelectButton="True" />
			   <asp:BoundField DataField="UserID" HeaderText="UserID" 
				   SortExpression="UserID" />
			   <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
			   <asp:BoundField DataField="Country" HeaderText="Country" 
				   SortExpression="Country" />
			   <asp:BoundField DataField="Age" HeaderText="Age" SortExpression="Age" />
		   </Columns>
		</asp:GridView>

الان نفذ الكود كل شي جميع ورائع و لم نقم بالكثير من التغير

والان قم بختيار احد الاسطر و قم بالترتيب :(

هنا ظهرت مشلكة و هي ان السطر لا يتغير مع الاختيار الحل موجود ولكن يجب عليك استخدام (Keyboard) لوحة المفاتيح

الطريقة هي خزن السطر المختار في ال ViewState

ولكن كيف سوف نقوم بتميز السطر عن بقية الاسطر( لا يمكن استخدام ال SelectedIndex لانها قيمة متغيرة) :(

ولهذا لعد قمت باضافة ال DataKey لل GridView

في البداية سوف اقوم بخزم الDataKey في ال GridView ثم استرجاع هذا القيمة بعد الترتيب

سوف اقوم بخزن الuserID بسبب لا يوجد سطران بنفس القيمة

DataKeyNames="userID"

 <asp:GridView ID="GV0" runat="server" DataSourceID="ODS0" AllowSorting="True" DataKeyNames="userID"
			AutoGenerateColumns="False" SelectedRowStyle-BackColor="Brown" 
			ondatabound="GV0_DataBound" onselectedindexchanged="GV0_SelectedIndexChanged" >
		   <Columns>
			   <asp:CommandField ShowSelectButton="True" />
			   <asp:BoundField DataField="UserID" HeaderText="UserID" 
				   SortExpression="UserID" />
			   <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
			   <asp:BoundField DataField="Country" HeaderText="Country" 
				   SortExpression="Country" />
			   <asp:BoundField DataField="Age" HeaderText="Age" SortExpression="Age" />
		   </Columns>
		</asp:GridView>

افضل مكان لخزن السطر هي عند الايفينت SelectedIndexChanged الخاص ب ViewGrid

	protected void GV0_SelectedIndexChanged(object sender, EventArgs e)
	{
		if (GV0.SelectedIndex != -1)
		{
			ViewState["SelectedRowValue"] = GV0.SelectedValue.ToString();
		}
	}

الان سوف نستعيد القيمة من الViewState بعد الانتهاء العملية

protected void gridEmployees_DataBound(object sender, EventArgs e)
{
if (ViewState["SelectedValue"] != null)
{
string selectedValue = (string)ViewState["SelectedValue"];
// Reselect the last selected row.
foreach (GridViewRow row in gridEmployees.Rows)
{
string keyValue = gridEmployees.DataKeys[row.RowIndex].Value.ToString();
if (keyValue == selectedValue)
{
gridEmployees.SelectedIndex = row.RowIndex;
return;
}
}
}
}

انصح الجميع بالعمل على طريقة الاخ Newbie لان ال DataSet تستهلك الذاكرة ولكن يوجد بعد الحلول قد تجدها بهذا الرد

شكرا Newbie على العمل الرائع

#18

شكرا slayer666

لم اكن اعرف انك تقوم بتطوير وتكملة الموضوع ,, اعجبني الموضوع فأردت ان اضيف عليه ,,

هل اتيحت لك فرصة التجربة ؟

هل هناك إضافات للموضوع او هناك ما يمكن مناقشته نظريا او عمليا؟

The World Must Be Crazy

#19

شكرا اخ newbie

ردودك جمعيها رائعة و قد استفد الكثر منها

اما بخصوص التطوري لقد قمت بعمل تغيرات بسيطة على الكلاس (بسيطة جداً) ولا يفرق عن الكلاس التي قمت انت بكتابته , التغيرات في ما يناسب البرنامج الذي اقوم بكتابته :blush:

ولدي ملاحظة واحدة فقط في رئي الشخصي المتواضع تستخدم الطريقة (طريقة New newbie) مع البيانات الدائمة التغير

اما اذا كانت البيانات دائما الاستخدام افضل العمل مع ال DataSet بسبب الCaching و تجنب الاتصال بقواعد البيانات مرارا و تكراراً

و اتمنى النقاش في هذا الموضوع لا ينتهي :D بسبب اني تعلمت الكثير منه و اتمنى ما قمت بكتابه قام بفائدة احد

و اي سؤال الاخ newbie حاضر :lol:

#20

شكرا أخى الكريم على هذا الدرس الرائع

وجزاك الله عنا خيرا

Oracle Developer

#21

يا اخوان

جزاكم الله خير

لو ممكن تجاوبوني على سؤالي

عملت objectdatasourc

و عملت datalist

و كل الامور تمام حتى الكلاسات

و لكن عندما اعرض الصفحة في المتصفح فانه لا يظهر اي بيانات ضمن الداتاليست

فقط يظهر اسم ال lable من ال item template و دون ان تجلب البيانات من قاعدة البيانات من الحقل الذي سويت له bind

مواضيع مشابهة