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

Linq To Dataset

بدأه محمد سامر أبو سلو في 15 أبريل 2008 · 3 رد · 2,277 مشاهدة · في ADO.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

يعتبر المجال System.Data.Dataset تمثيلا للبيانات في الذاكرة وهو مفيد في الوصول إلى نسخة منفصلة من البيانات التي تأتي من مصدر بيانات خارجي. وبغض النظر عن ذلك المصدر فالتمثيل الداخلي للـ DataSet يكون بالصورة العلائقية متضمنا الجداول والشروط والعلاقات بين الجداول. وبكلمات أخرى يمكنك أن تعتبر الـ DataSet قاعدة بيانات في الذاكرة فهي تعتبر هدف جيد لأدوات Linq.

استخدام Linq لتحميل مجموعة البيانات

يمكن تحميل الـ DataSet عن طريق الاستعلام من قاعدة بيانات علائقية وأحد الطرق لعمل ذلك هو عن طريق DataAdapter كما هو ظاهر في الكود

DataSet ds = new DataSet("CustomerOrders");
SqlDataAdapter da = new SqlDataAdapter( QueryOrders, ConnectionString );
da.SelectCommand.Parameters.AddWithValue( "@CustomerID", "QUICK" );
da.TableMappings.Add( "Table", "Orders" );
da.TableMappings.Add( "Table1", "OrderDetails" );
da.Fill( ds );

const string ConnectionString = "Database=Northwind;Trusted_Connection=yes";
const string QueryOrders = @"
SET @CustomerID = 'QUICK'
SELECT  OrderID, OrderDate, Freight, ShipName,
		ShipAddress, ShipCity, ShipCountry
FROM	Orders
WHERE   CustomerID = @CustomerID

SELECT	 od.OrderID, od.UnitPrice, od.Quantity, od.Discount,
		   p.[ProductName]
FROM	   [Order Details] od
INNER JOIN Orders o
	  ON   o.[OrderID] = od.[OrderID]
LEFT JOIN  Products p
	 ON	p.[ProductID] = od.[ProductID]
WHERE	  o.CustomerID

حيث يقوم الكود السابق بجمع جدولي بيانات في مجموعة بيانات واحدة توافق الطلبات المقدمة من قبل زبون معين

استخدام Linq للاستعلام من مجموعة البيانات

يمكن الاستعلام عن جدول البيانات DataTable باستخدام Linq تماما كأي قائمة قابلة للتعداد Enumerable<T> مع أنه لا يحققها وهنا عليك استدعاء الدالة الموسعة AsEnumerable التي توسع جدول البيانات للحصول على غلاف يحقق تلك الواجهة.

ويتم تكوين القائمة من مجموعة من أغراض DataRow وهكذا يجب عليك استخدام خصائص سطر البيانات DataRow للحصول على قيم الحقول. مما يمكنك من استدعاء عنصر عائد لسطر البيانات DataRow بدلا من استخدام تعبير الاستعلام عبر جدول البيانات DataTable حيث يمكنك استخدام طريقة الوصول Field<T> بدلا من استخدام التحويل المباشر على النتيجة عند استخدام طريقة الوصول القياسية. ويرينا الاستعلام التالي الطلبات الوقعة في عام 1998 أو ما بعد

DataSet ds = LoadDataSetUsingDataAdapter();
DataTable orders = ds.Tables["Orders"];
DataTable orderDetails = ds.Tables["OrderDetails"];

var query =
	from	o in orders.AsEnumerable()
	where   o.Field<DateTime>( "OrderDate" ).Year >= 1998
	orderby o.Field<DateTime>( "OrderDate" ) descending
	select  o;

والطريقتان AsEnumerable و Field<T> هما طريقتان موسعتان لجدول البيانات DataTable و سطر البيانات DataRow وهما معرفتان في مجالي الأسماء System.Data.DataTableExtensions و System.Data.DataRowExtensions.

فعندما يكون لديك عدة أغراض DataTable في DataSet قد تريد استخدام نوعا من الدمج والاستعلام التالي يقوم بجمع مجموع كل طلب من العام 1998 إلى الوقت الحاضر

DataSet ds = LoadDataSetUsingDataAdapter();
DataTable orders = ds.Tables["Orders"];
DataTable orderDetails = ds.Tables["OrderDetails"];

var query =
	from	o in orders.AsEnumerable()
	join	od in orderDetails.AsEnumerable()
			on o.Field<int>( "OrderID" ) equals od.Field<int>( "OrderID" )
			into orderLines
	where   o.Field<DateTime>( "OrderDate" ).Year >= 1998
	orderby o.Field<DateTime>( "OrderDate" ) descending
	select  new { OrderID = o.Field<int>( "OrderID" ),
				  OrderDate = o.Field<DateTime>( "OrderDate" ),
				  Amount = orderLines.Sum(
							   od => od.Field<decimal>( "UnitPrice" )
									 * od.Field<short>( "Quantity" ) ) };

في المثال السابق قمنا بتحديد علاقة بين الجدولين Orders و OrdersDetails عبر صيغة دمج Join Syntax وإن كانت الـ DataSet تحتوي على علاقات بينهما فـ Linq يستفيد منها وفي الاستعلام التالي نستخدم GetChildRows للحصول على أسطر تفاصيل الطلب بدلا عن دمج الجدولين

DataSet ds = LoadDataSetUsingDataAdapter();
DataTable orders = ds.Tables["Orders"];
DataTable orderDetails = ds.Tables["OrderDetails"];
ds.Relations.Add( "OrderDetails",
				  orders.Columns["OrderID"],
				  orderDetails.Columns["OrderID"]);

var query =
	from	o in orders.AsEnumerable()
	where   o.Field<DateTime>( "OrderDate" ).Year >= 1998
	orderby o.Field<DateTime>( "OrderDate" ) descending
	select  new { OrderID = o.Field<int>( "OrderID" ),
				  OrderDate = o.Field<DateTime>( "OrderDate" ),
				  Amount = o.GetChildRows( "OrderDetails" ).Sum(
							   od => od.Field<decimal>( "UnitPrice" )
									 * od.Field<short>( "Quantity" ) ) };

استخدام Linq للاستعلام من Typed Dataset

يمكن الاستعلام من Typed DataSet بطريقة أبسط لأنه يصبح من غير الضروري استخدام الطريقتين Field<T> و AsEnumerable. فإن قمت بإنشاء Typed DataSet باستخدام فيجول ستوديو فستكون فئات Typed DataTable الخاصة بك مشتقة من الفئة TypedTableBase<T> والتي تحقق الواجهة IEnumerable<T> ولهذا السبب أنت غير مضطر لاستدعاء الدالة AsEnumerable.

والاستعلام السابق الذي يستخدم لرفع العلاقات الموجودة في الـ DataSet يمكن أن يعاد كتابته باستخدام Typed DataSet بالشكل

var query =
	from	o in ds.Orders
	where   o.OrderDate.Year >= 1998
	orderby o.OrderDate descending
	select  new { o.OrderID, o.OrderDate,
				  Amount = o.GetOrder_DetailsRows().Sum(
							   od => od.UnitPrice * od.Quantity ) };

وكما ترى فصيغة الاستعلام تكون أبسط ومشابهة للاستعلام السابق ومع ذلك يمكنك استخدام مخطط محدد سلفا Typed DataSet للاستعلام من الـ DataSet بطريقة مشابهة مما يمنع استخدام هذه الصيغة مع DataSet تحتوي على مخطط مرن في زمن التنفيذ وهذا لا يعني انه عليك استخدام UnTyped DataSet ولكنه يؤكد على أن UnTyped DataSet يمكن الاستعلام منها فقط باستخدام محدد الوصول Field<T>

الوصول إلى بيانات UnTyped DataSet

الوصول إلى البيانات في UnTyped DataSet يتطلب استخدام محددات الوصول Field<T> و SetField<T> للوصول إلى قيم الحقول وتغييرها ويعتبر محددي الوصول هذين هامين بسبب أن القيمة Null في قاعدة البيانات تمثل بالطريقة IsNull تعيد القيمة True وعليك التحقق من هذا الشرط في كل مرة تحاول فيها الوصول إلى عمود من أجل تجنب أخطاء التحويل واستخدام محددات الوصول هذه مسموح في أي DataRow أو DataTable حتى خارج تعبير الاستعلام كما هو ظاهر من الكود

foreach( DataRow r in orderDetails.Rows ) {
	if (r.Field<decimal>( "UnitPrice" ) < 10 ){
		r.SetField<decimal>( "UnitPrice", 10 );
	}
}

مترجم بتصرف

عن عائشة رضي الله عنها أن النبي صلى الله عليه وسلم قال: إن الله يحب إذا عمل أحدكم عملا أن يتقنه

نعيب زماننا والعيب فينا ... وما لزماننا عيب سوانا

ونهجو ذا الزمان بغير ذنب ... ولو نطق الزمان لنا هجانا

محمد سامر أبو سلو

#2

أٌقرأ الموضوع و لو في استفسار أرجع لك...إن شاء الله يكون كل شيء واضح...

ألف شكر ...

سبحان الله و الحمد لله و الله أكبر

#3

للإستزادة من هذا الموضوع الذى طرحة الأستاذ محمد حمل الملف التالى :

Start_LINQ.zip

[/وسط]

#4

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

الـ LINQ هي اللي دفعتني لاستخدام الفيجوال ستديو 2008

و أول ما قرأت في الـ LINQ قرأت موضوع لك .. اسعدك الله في الدنيا و الآخرة ..

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