EF

01 – مبادئ اطار عمل الكينونة

اطار عمل الكينونة
اطار عمل الكينونة

سنتعلم مبادي اطار عمل الكينونة عبر الشرح خطوة فخطوة. سنستخدم الإصدار 6.0 بالإضافة لفجوال استديو 2015.

في الجدول التالي نستعرض كل الإصدارات المهمة لاطار عمل الكينونة

اصدار EF الخصائص التي قدمها
EF 3.5 الدعم الأساسي لـO/RM مع مقاربة قاعدة البيانات أولا.
EF 4.0 دعم POCO, والتحميل البطيء Lazy loading, وتحسين الاختبارية بالإضافة لتخصيص توليد الاكواد ومقاربة النموذج اولا Model First.
EF 4.1 اول اتاحة في NuGet تبسيط واجهة برمجة التطبيقات DBContext  في ObjectContext بالإضافة لمقاربة الشفرة أولا Code First. وصدر EF 4.1.1 لمعالجة أخطاء 4.1..
EF 4.3 خاصية تهجير الشفرة أولا التي تتيح انشاء قاعدة البيانات باستخدام الشفرة أولا ليتم تغييرها باضطراد مع تضمين نماذج الشفرة أولا. واصدر EF 4.3.1 لترقيع أخطاء EF 4.3.
EF 5.0 اعلن ان EF سيكون مفتوح المصدر. وقدم دعم الأنواع التعداديةEnum ودوال جدولية القيمة table-valued functions وأنواع البيانات المكانيةspatial وتعدد المخططات multiple-diagrams للنموذجmodel وتلوين الاشكال في واجهة التصميم مع تنفيذ الإجراءات المخزنة. كما تم إضافة تحسينات مهمة لادوات EF Power Tools.
EF 6.0 – Current release اخر اصدار تقريبا EF 6.0/6.1. يحوي الكثير من الخصائص الجديدة في الشفرة أولا وفي مصمم EF مثل الاستعلامات والحفظ غير المتزامن وغيرها

ملحوظة: ظهر بعده EF Core لكننا لن نتطرق اليه الان

للمزيد من التفاصيل زر صفحة ميكروسوفت MSDN كما يمكن ان تزور صفحة دروس Code-First Tutorial  لتتعرف عليها.

المتطلبات:  معرفة باساسيات اطار العمل .Net ولغة C# والفيجوال ستديو بالإضافة الي MS SQL Server.

المصدر: معظم الدروس مترجمة من موقع تمارين اطار عمل الكينونة

Advertisements
WPF, دورات, ربط البيانات

اساسيات مشروع WPF –MVVM باستخدام EF

maxresdefault

مقدمة

المشروع عبارة عن مشروع ثلاثي الطبقات (طبقة البيانات Data layer وطبقة الاعمال Business layer وطبقة العرض Presentation layer) ويتكون من صندوقي لائحة comboboxes وصندوق نص textbox  ( في النافذة الرئيسة MainWindow.xaml) بالاضافة لنموذج ADO.NET Entity Model  واحد يحوي جدولين ( المؤلف Author والكتاب Book) ونموذج عرض واحد ViewModel بالاسم MainWindowViewModel.cs. وقد انشئ هذا المشروع باستخدام فيجوال ستديو 2012 ووندوز 8.1 لكن يمكنك استخدام النسخة التي تريدها.

في صفحة البداية للمشروع MainWindowViewModel  سنعبيء كينونة جدول المؤلف Author التي تكون مصدر البيانات لصندوق اللائحة الاول (سنسميه cmbAuthor) وعند اختيار مؤلف من هذا الصندوق سيتم ملء صندوق اللائحة الثاني (cmbBook) بالكتب لهذا المؤلف من كينونة جدول الكتب. وعند اختيار كتاب من هذه اللائحة فسيتم ملء حقل الوصف Description  بالوصف لهذا الكتاب في صندوق النص.

اولا انشانا جدولين بقاعدة البيانات (اي قاعدة بيانات) في خادم سيكوال SQL Server. وجدول المؤلف Author  (الجدول الرئيس Master table) بينما جدول الكتب ( جدول التفاصيل Detail table). ويرتبط هاذين الجدول بقيدي المفتاح الاساس والمفتاح الاجنبي PK-FK.

وادناه اكواد سيكوال لانشاء الجدولين:

create table Author (AuthorId int primary key, AuthorName nvarchar(50))

create table Book (BookId int primary key, AuthorId int, Title nvarchar(50), Description nvarchar(200), Price money)

alter table Book add constraint FK_Book_Author foreign key (AuthorId) references Author (AuthorId)

insert into Author values (1, ‘Gambardella, Matthew’)

insert into Author values (2, ‘Ralls, Kim’)

insert into Author values (3, ‘Corets, Eva’)

insert into Book values (1, 1, ‘XML Developers Guide’, ‘An in-depth look at creating applications with XML.’, 4.95)

insert into Book values (2, 1, ‘Foods of the world.’, ‘Simply a book about food.’,  5.95)

insert into Book values (3, 1, ‘Cars’, ‘A book about cars.’,  8.95)

insert into Book values (4, 2, ‘Scarecrows’, ‘This be could horror or agriculture.’, 4.15)

insert into Book values (5, 3, ‘Book of blue’, ‘First in a series of books about colors’,  6.30)

insert into Book values (6, 3, ‘EF’, ‘Some tips and trics on Entity Frameworks’,  3.45)

انشأنا بعدها تطبيق WPF  وسميناه Wpf_EF_Mvvm_sample. ثم قمنا باضافة ADO.NET Entity Model (سيعمل مع EF5 أو EF6). وسيعمل نموذج الكينونة هذا كنموذج لنمط نموذج – عرض – نموذج عرض MVVM. وقمنا بتسمية ملف .edmx باسم AuthorBook. وقمنا باستخدام المعالج للانشاء من قاعدة بيانات Generate from Database واخترنا الخادم المطلوب الذي يحوي قاعدة البيانات التي انشانا بها الجدولين. وسمينا سياق الكينونة AuthorBookEntities. ثم بعد نقر التالي اخترنا الجدولين Author و Book. ثم غيرنا اسم النموذج (اسفل نفس نافذة صندوق الحوار التي اخترنا منها الجدولين) غيؤناه الي AuthorBookModel ثم نقرنا علي موافق OK. وهكذا تم انشاء نموذج الكينونةEntity Model. وهذه هي طبقة البيانات Data layer. وسيستخدم نموذج الكينونة هذا DBContext.

ثم اضفنا الفئة MainWindowViewModel.cs للمشروع . اضفناها مباشرة لمجلد المشروع الرئيس(نفس المجلد الذي يحوي MainWindow.xaml) حتي يظل الامر بسيطا.

وفي الفئة MainWindowViewModel اضفنا الموجه using System.ComponentModel  للواجهة INotifyPropertyChanged والتي سنحتاج لتضمينها لنستخدم الخصائص للقيام بالعمليات. واضفنا ايضا الموجه using System.Runtime.Compilerservices ااتزييل [CallerMemberName] الذي سيستخدم المنهج NotifyPropertyChanged في تضمين INotifyPropertyChanged. وهي ميزة جيدة جدا اذ ستلغي الحوجة لتضمين اسماء الخواص عند استدعاء NotifyPropertyChanged() في خصائص MainWindowViewModel (كانت ستكون NotifyPropertyChanged(“somePropertyName”);).

وستكون الاكواد بملف MainWindowViewModel.cs. وهي طبقة الاعمالل Business layer:

using System;

using System.Collections.Generic;

using System.Linq;

using System.ComponentModel;

using System.Runtime.CompilerServices;

namespace Wpf_EF_sample

{

    class MainWindowViewModel : INotifyPropertyChanged

    {

        AuthorBookEntities ctx = new AuthorBookEntities();

        public MainWindowViewModel()

        {

            FillAuthors();

        }

        private void FillAuthors()

        {

            var q = (from a in ctx.Authors

                     select a).ToList();

            this.Authors = q;

        }

        private List<Author> _authors;

        public List<Author> Authors

        {

            get  {  return _authors;  }

            set

            {

                _authors = value;

                NotifyPropertyChanged();

            }

        }

        private Author _selectedAuthor;

        public Author SelectedAuthor

        {

            get {return _selectedAuthor;  }

            set

            {

                _selectedAuthor = value;

                NotifyPropertyChanged();

                FillBook();

            }

        }

        private void FillBook()

        {

            Author author = this.SelectedAuthor;

            var q = (from book in ctx.Books

                     orderby book.Title

                     where book.AuthorId == author.AuthorId

                     select book).ToList();

            this.Books = q;

        }

        private List<Book> _books;

        public List<Book> Books

        {

            get   {  return _books;    }

            set

            {

                _books = value;

                NotifyPropertyChanged();

            }

        }

        private Book _selectedBook;

        public Book SelectedBook

        {

            get{ return _selectedBook;       }

            set

            {

                _selectedBook = value;

                NotifyPropertyChanged();

            }

        }

        public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]

protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = “”)

        {

           PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        }

    }

}

وفي فئة MainWindowViewModel ننشئ اولا الكائن السياقي:

AuthorBookEntities ctx = new AuthorBookEntities();

ثم نقوم بتحميل اول كينونة/لائحة (المؤلفين) في الباني باستخدام المنهج FillAuthors(). لاحظ حوجتنا لذكر LINQ  لانه لايمكن لمجموعة البيانات DBSet ان تستخدم مباشرة من قبل التحكم وهي مصدر البيانات بالنسبة لخاصية اللائحة List  التي هي ItemSource لصندوق اللائحة cmbAuthor. والخاصية SelectedItem لهذا الصندوق ستربط مع الخاصية SelectedAuthor في MainWindowViewModel. وعند تنفيذ هذه الخاصية فسيتم استدعاء المنهج FillBook وكتب الملف المحدد ستملأ لائحة الكتب اي الخاصية ItemSource لصندوق اللائحة cmbBook.

الان تم ملء صندوقي اللائحة الاثنين. العمل الممتع هو عند اختيار عنصر من خاصية SelectedItem لنصدوق لائحة الكتب المرتبطة مع الخاصية SelectedBook والتي ستحتوي علي صف واحد من لائحة الكتب. والخاصية Text لمربع النص ستربط مع SelectedBook.Description بحيث انه عند اختيار عنصر من لائحة الكتب cmbBook فان محتويات الحقل Description بالنسبة للكتاب المختار ستظهر تلقائيا في صندوق النص. ملاجظة: هذا يمكن ان يقدم تبعية خفيفة في اسماء الحقول لجدول الكتب باستحدام هذه التقنية. يمكننا الالتفاف علي هذه الحالة بانشاء منهج لجلب قيمة الوصف Description للكتاب المختار. ثم انشاء خاصية لصندوق النص لنقوم بربطها لما سيمرر قيمة الوصف.

سكون MainWindowViewModel  طبقة الاعمال Business layer.

اما الطبقة الثالثة فهي طبقة العرض Presentation layer ستكون MainWindow.xaml وسيحوي هذا الملف كل اكواد زامل التي سترتبط مع الخصائص في MainWindowViewModel  لكن قبل العمل مع زامل نحتاج لبناء التطبيق حتي يتم انشاء مجمع التطبيق assembly وهذا سينشئ  سياق البيانات DataContext ليتم استخدامه من قبل MainWindow.xaml.

لاحظ ان التطبيق يمكن ان يترجم بدون طبقة العرض وهذا مثال علي مفهوم “مراعات الفصل separation of concerns” الذي يعد من مفاهيم نمط MVVM المهمة. في النماذج WinForms ستقوم بربط مجموعة اكواد مع احداث التحكم بالنموذج. فمثلا لو قمت بحذف تحكم من النموذج فلن تتم ترجمة المشروع. وهذا مثال علي مفهوم البرمجة المترابطة في برمجة WinForms. ةقد قام MVVM بحل هذا الاشكال عبر فصل الاكواد من واجهة المستخدم واستخدم الربط Binding و الاوامر commands للتفاعل بين الواجهة UI والاكواد (طلقة الاعمال Business layer). بعد ترجمة المشروع لدينا مجمع يمكن للنافذة الرئيسة MainWindow  ( العرض view) الارتباط معه. اولا نضيف مرجع لموضع MainWindowViewModel (وهو المجلد الجزري). اي سنضيف السطر التالي الي اعلي MainWindow.xaml .

xmlns:vm=”clr-namespace:Wpf_EF_sample”

ثم نضيف سياق البيانات

<Window.DataContext>

    <vm:MainWindowViewModel />

</Window.DataContext>

ويمكن ان يتم هذا في ملف الشفرة المضمنة (MainWindow.xaml.cs). واكواد زامل لطبقة العرض ستكون:

<Window x:Class=”Wpf_EF_sample.MainWindow”

        xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

        xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

        xmlns:vm=”clr-namespace:Wpf_EF_sample”

        Title=”MainWindow” Height=”350″ Width=”525″>

    <Window.DataContext>

        <vm:MainWindowViewModel />

    </Window.DataContext>

    <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width=”180″ />

            <ColumnDefinition Width=”*” />

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition Height=”25″ />

            <RowDefinition Height=”*” />

        </Grid.RowDefinitions>

        <ComboBox DisplayMemberPath=”AuthorName” ItemsSource=”{Binding Authors}”

                      Grid.Row=”0″ Grid.Column=”0″ Grid.ColumnSpan=”1″ Name=”combo1″ SelectedItem=”{Binding SelectedAuthor}” />

        <ComboBox DisplayMemberPath=”Title” ItemsSource=”{Binding Books}”

                      Grid.Row=”0″ Grid.Column=”1″ Grid.ColumnSpan=”1″ Name=”combo2″ SelectedItem=”{Binding SelectedBook}” />

        <TextBlock Grid.Row=”1″ Grid.Column=”0″ Grid.ColumnSpan=”2″ Name=”tbDesc” Text=”{Binding SelectedBook.Description}”/>

    </Grid>

</Window>

مترجم بتصرف المصدر

الصورة من DCOM Engineering, LLC

WPF, دورات, ربط البيانات

ربط البيانات في WPF

سنعرف كيف نربط انواع POCO  مع تحكمات WPF في نماذج “رئيس-تفاصيل”. وسنستخدم اطار عمل الكينونة Entity Framework لملء الكائنات بالبيانات من قاعدة البيانات ولتتبع التعديلات ولحفظ البيانات بقاعدة البيانات.

سنقوم بتعريف نوعين يتشاركان علاقة رأس باطراف: التصنيفات Category  (الرئيس) والمنتجات (التفاصيل) Product . ثم سنستخدم ادوات الفيجوال ستديو لربط النوعين المعرفين في النموذج model مع تحكمات WPF. يتيح لنا اطار عمل ربط بيانات WPF التنقل  بين الكائنات المرتبطة: واختيار الصفوف في الجدول الرئيس master view ليتم نحديث بيانات جدول التفاصيل detail view بالبيانات المتوافقة.

استخدام خيار كائن ‘Object’ لانشاء مصادر بيانات WPF

في الاصدارات السابقة من EF كنا نستخدم الخيار الموصي به Database عند انشاءنا لقاعدة بيانات جديدة بناء علي نموذج انشيء باستخدام مصمم EF. لان المصمم سيولد لنا السياق المشتق من الكائن السياقي ObjectContext وفئات الكينونة المشتقة من كائن الكينونة EntityObject. وسيساعدك استخدام الخيار Database علي كتابة افضل الاكواد للتفاعل مع واجهة برمجة التطبيقات.

يولد مصمم EF في فيجوال ستديو 2012 و 23013 سياق مشتق من سياق البيانات DbContext مع فئات لكينونة POCO . وعند استخدام سطح واجهة برمجة التطبيقات لسياق البيانات DbContext API فيجب علينا استخدام الخيار “كائن Objectعند انشاء مصدر بيانات جديد .

المتطلبات

يجب ان يكون لديك فيجوال ستديو 2012 او 2013 لكن يمكنك تنفيذ التدريب باستخدام 2010 ايضا لكنك ستحتاج لتثبيت NuGet

انشاء التطبيق

  • نفتح فيجوال ستديو
  • File -> New -> Project….
  • اختر Windows من اللوحة اليسري ثم WPFApplication في اللوحة الوسطي
  • أدخل WPFwithEFSample  في خانة الاسم
  • ثم OK

 

تثبيت حزمة NuGet لاطار عمل الكينونة EF

من مستععرض الحل ننقر بالزر الايمن علي اسم التطبيقWinFormswithEFSample

  • اختر Manage NuGet Packages…
  • ومن صندوق الحوار الذي يظهر اختر تبويب Online ثم اختر جزمة EntityFramework
  • انقر علي تثبيت Install
    ملاحظة : بالاضافة الي مجمع اطار عمل الكينونة فيتم اضافة مرجع الي مجال الاسماء ComponentModel.DataAnnotations واذا كان لدي التطبيق مرجع الي System.Data.Entity فسيتم ازالته عند تثبيت حزمة EntityFramework. ولم يعد مجمع System.Data.Entity مستخدما مع تطبيقات EF 6.

 

تعريف النموذج

يمكننا تضمين النموذج سواء باستخدام التشفير اولا Code First أو باستخدام مصمم EF. لذا يمكنك استخدام واحد من الخيارين التاليين.

الخيار 1: تعريف النموذج باستخدام التشفير اولا Code First

عند استخدامنا لمقاربة التكويد اولا فاننا نبدأ عادة بكتابة فئات اطار عمل دوت نت التي تعرف نموذجنا المفاهيمي.

  • نضيف فئة جديدة لمشروع WPFwithEFSample:
    • ننقر بالزر الايمن علي اسم المشروع
    • نختر Add ثم عنصر جديد New Item
  • نختر فئة Class ثم نسمها Product

استبدال تعريف الفئة Product  بالاكواد التالية

namespace WPFwithEFSample
{
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }

public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
}

  • ثم نضيف الفئة Category بالتعريف التالي :

using System.Collections.ObjectModel;

namespace WPFwithEFSample
{
public class Category
{
public Category()
{
this.Products = new ObservableCollection<Product>();
}
public int CategoryId { get; set; }
public string Name { get; set; }

public virtual ObservableCollection<Product> Products { get; private set; }
}
}

خاصية Products في فئة Category والخاصية Category في الفئة Product هي خواص تنقل navigation properties. وفي اطار عمل الكينونة فان خواص التنقل تعطينا القدرة علي التنقل في العلاقة بين نوعي كينونة.

وبالاضافة لتعريف الكينونات فنحتاج لتعريف فئة مشتقة من DbContext ونعلن عن خواص من نوع DbSet<TEntity> . وتمكن خواص DbSet<TEntity>  السياق من معرفة النوع الذي تريد تضمينه في النموذج.

ويشتق مثيل DbContext نوع يقوم بادارة الكائنات في وقت التنفيذ ويشمل عملية تعبئة الكائنات بالبيانات من قاعدة البيانات وتتبع التغيرات (التعديلات) وحفظ البيانات بقاعدة البيانات.

  • اضفة فئة جديدة بالاسم ProductContext للمشروع بالتعريف التالي:

using System.Data.Entity;

namespace WPFwithEFSample
{
public class ProductContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
}

الان قم بترجمة المشروع.

الخيار 2: تعريف النموذج باستخدام مقاربة قاعدة البيانات اولا  Database First

انشاء قاعدة بيانات موجودة

يختلف خادم البيانات المثبت مع الفيجوال ستديو باختلاف نسخة الفجوال ستديو لديك:

  • اذا كنت تستخدم فيجوال ستديو 2010 فستنشيء قاعدة بيانات SQL Express.
  • اذا كنت تستخدم فيجوال ستديو 2012 فستنشيء قاعدة بيانات LocalDb.

 

لنقم بانشاء قاعدة البيانات

  • View -> Server Explorer
  • ننقر بالزر الايمن علي Data Connections -> Add Connection…

اذا لم تكن متصلا بقاعدة البيانات من مستعرض الخادم Server Explorer من قبل فستحتاج لاختيار Microsoft SQL Server كمصدر للبيانات

اتصل أما بالمحلية LocalDb  والتي تكون  ((localdb)\v11.0) أو بالسريعة SQL Express  والتي تكون (.\SQLEXPRESS) علي حسب الخادم المثبت لديك. ثم ادخل Products كاسم لقاعدة البيانات

اختر موافق OK وسيتم سؤالك ما اذا كنت تريد انشاء قاعدة بيانات جديدة، أختر نعم Yes

  • ستظهر الان قاعدة البيانات الجديدة في مستعرض الخادم Server Explorer ننقر بالزر الايمن عليها ثم نختر استعلام جديد New Query
  • انسخ جمل SQL التالية للاستعلام الجديد ثم انقر علي الاستعلام بالزر الايمن واختر تنفيذ Execute

CREATE TABLE [dbo].[Categories] (
[CategoryId] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
CONSTRAINT [PK_dbo.Categories] PRIMARY KEY ([CategoryId])
)

CREATE TABLE [dbo].[Products] (
[ProductId] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
[CategoryId] [int] NOT NULL,
CONSTRAINT [PK_dbo.Products] PRIMARY KEY ([ProductId])
)

CREATE INDEX [IX_CategoryId] ON [dbo].[Products]([CategoryId])

ALTER TABLE [dbo].[Products] ADD CONSTRAINT [FK_dbo.Products_dbo.Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [dbo].[Categories] ([CategoryId]) ON DELETE CASCADE

الهندسة العكسية للنموذج Reverse Engineer Model

سنقوم باستخدام مصمم الكينونات والذي يضمن كجزء من الفيجوال ستديو لانشاء نموذجنا.

  • Project -> Add New Item…
  • اختر Data من القائمة اليسري ثم اختر ADO.NET Entity Data Model
  • ادخل في خانة الاسم ProductModel ثم انقر علي OK
  • سيظهر لنا معالج نموذج بيانات الكينونة Entity Data Model Wizard

اختر Generate from Database ثم انقر علي Next

نختر رابطنا لقاعدة البيانات التي انشأناها في القسم الاول وندخل الاسم ProductContext  ليكون اسما لسلسلة الاتصال ثم ننقر التالي Next

ننقر علي صندوق التحقق بجوار الجداول Tables لاستيراد كل الجداول ثم ننقر علي انهاء Finish

عند اكمال عمليات الهندسة العكسية فستم اضافة نموذج جديد للمشروع وسيفتح حتي نتمكن من رؤية مصمم اطار عمل الكينونة. كما سيضاف ملف App.config للمشروع ويحوي بيانات الاتصال بقاعدة البيانات.

تحديث الكود المولد لربط البيانات

يولد EF اكواد من نموذجك مستخدما قوالب T4. وتأتي هذه القوالب مع فيجوال ستديو او يمكننا ان نقوم بتنزيلها من معرض الفيجوال ستديو. وتحوي الكينونات المولدة من قبل هذه القوالب خواص ICollection<T>. وبالرغم من ان WPF تفضل استخدام ObservableCollection لخواص التجميعة عند التعامل مع ربط البيانات بحيث تستطيع WPF مراقبة التغيرات الحادثة في التجميعة. لهذا سنقوم بتعديل القوالب لتستخدم التجميعة المراقبة ObservableCollection.

  • نفتح مستعرض الحل Solution Explorer ونبحث عن ملف ProductModel.edmx

ثم نبحث عن ملف  ProductModel.tt الذي سيكون محتو تحت ملف ProductModel.edmx

  • ننقر نقرا مزدوجا علي ملف  ProductModel.tt لفتحه في محرر الفجوال ستديو
  • نبحث عن ورود ICollection مرتين  ونقوم باستبداله بكلمة ObservableCollection. تقريبا ستجدهما في السطرين 296  و 484
  • نبحث عن اول ورود لكلمة HashSet  ونستبدلها بكلمة ObservableCollection تقريبا ستجدها بالسطر 50. لكن انتبه ولاتقم باستبدالها عند ورودها للمرة الثانية.
  • ابحث عن System.Collections.Generic التي ترد مرة واحدة فقط واستبدلها بالجملة System.Collections.ObjectModel. وستكون تقريبا بالسطر 424
  • نحفظ الان ملف ProductModel.tt. وسيتسبب هذا في اعادة توليد اكواد الكينونات. واذا لم يحدث هذا تلقائيا فقم بالنقر بالزر الايمن علي ملف ProductModel.tt ثم اختر Run Custom Tool

اذا قمت الان بفتح ملف Category.cs (وهو يوجد اسفل ملف ProductModel.tt) فستري ان تجميعة المنتجات قد اصبحت من النوع ObservableCollection<Product>

قم بترجمة المشروع.

التحميل المتأخر Lazy Loading

الخاصية Products في الفئة Category والخاصية Category في الفئة Product هي خواص تنقل. وكما ذكرنا فان خواص التنقل في اطار عمل الكينونة تمكننا من التنقل في العلاقة بين نوعي كينونتين.

وتعطينا EF الخيار في تحميل الكينونات المرتبطة من قاعدة البيانات تلقائيا عند أول مرة  نصل لخاصية التنقل. ومع هذا النوع من التحميل (يسمي التحميل المتأخر) يجب ان ننتبه انه مع اول وصول لخاصية التنقل سيتم تنفيذ استعلام منفصل بقاعدة البيانات اذا لم يكن المحتوي موجود بالفعل في السياق.

عند استخدام انواع الكينونة POCO فان EF ينفذ التحميل المتاخر بانشاء مثيل من انواع البروكسي المشتقة اثناء وقت التنفيذ ثم يتجاوز overriding الخواص التخيلية virtual properties في الفئة لاضافة خطاف تحميل loading hook. وللحصول علي تحميل متأخر للكائنات المرتبطة فيجب ان تعلن عن خاصية تنقل نحصل عليها باستخدام معرفات الوصول public و virtual ( Overridable في فيجوال بيسك) ويجب ان لاتكون الفئة يتيمة sealed  (غير قابلة للتجاوز NotOverridable في فيجوال بيسك). وعند استخدام قاعدة البيانات لخاصية التنقل لاول مرة  فستقوم بتفعيل التحميل المتأخر. ولهذا قمنا بجعل خواص التنقل تخيلية virtual لهذا السبب في مقاربة الشفرة أولا.

 

ربط الكائن بتحكم

نضيف الفئات التي عرفناها في النموذج كمصادر بيانات لتطبيق WPF.

  • ننقر نقرا مزدوجا علي MainWindow.xaml في مستعرض الحل لفتح النموذج الرئيس.
  • من القائمة الرئيسة نختر Project -> Add New Data Source …
  • نختر هنا الكائن Object ثم Next

في حوار احتيار كائنات البيانات نقوم بتوسيع WPFwithEFSample مرتبن ثم نختر Category

لاحوجة لاختيار مصدر البيانات Product لاننا سنصل اليه عبر الخاصية Product في مصدر البيبانات Category

  • انقر علي Finish.
  • ستفتح نافذة مصادر البيانات بجانب نافذة MainWindow.xaml
    اذا لم تظهر نذهب الي View -> Other Windows-> Data Sources
  • نقوم بتثبيت النافذة من ايقونة الدبوس حتي لاتختفي تلقائيا.
  • اختر مصدر البيانات Category ثم قم بسحبه الي النموذج

سيحدث التالي عند سحب هذا  المصدر للبيانات:

  • سيضاف مورد categoryViewSource  وتحكم categoryDataGrid لملف زامل.
  • وستضبط خاصية سياق البيانات DataContext بعنصر الشبكة الام علي {StaticResource categoryViewSource }. ويعمل مورد categoryViewSource كمصدر ربط لعنصر الشبكة الأب/الخارجي. من ثم سيرث عنصر الشبكة الداخلي قيمة سياق البيانات من الشبكة الام( ستضبط خاصية ItemsSource  لشبكة البيانات categoryDataGrid ستضبط علي {Binding})

<Window

        xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

        xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

        xmlns:d=”http://schemas.microsoft.com/expression/blend/2008&#8243; xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243; xmlns:local=”clr-namespace:WPFwithEFSample” mc:Ignorable=”d” x:Class=”WPFwithEFSample.MainWindow”

        Title=”MainWindow” Height=”350″ Width=”525″ Loaded=”Window_Loaded”>

    <Window.Resources>

        <CollectionViewSource x:Key=”categoryViewSource” d:DesignSource=”{d:DesignInstance {x:Type local:Category}, CreateList=True}”/>

    </Window.Resources>

    <Grid DataContext=”{StaticResource categoryViewSource}”>

        <DataGrid x:Name=”categoryDataGrid” RowDetailsVisibilityMode=”VisibleWhenSelected” Margin=”105,93,12,26″ ItemsSource=”{Binding}” EnableRowVirtualization=”True” AutoGenerateColumns=”False”>

            <DataGrid.Columns>

                <DataGridTextColumn x:Name=”categoryIdColumn” Width=”SizeToHeader” Header=”Category Id” Binding=”{Binding CategoryId}”/>

                <DataGridTextColumn x:Name=”nameColumn” Width=”SizeToHeader” Header=”Name” Binding=”{Binding Name}”/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

اضافة شبكة التفاصيل Details Grid

لدينا الان جدول لعرض التصنيفات لنضيف جدول (شبكة) اخر للتفاصيل لعرض منتجات كل تصنيف.

  • اختر الخاصية Products من اسفل مصدر بيانات Category واسحبها للنموذج
    • سيضاف كل من المورد categoryProductsViewSource  والشبكة productDataGrid  لملف الزامل
    • وسيضبك مسار الربط لهاذين الموردين ليكون Products
    • وسيتأكد رابط البيانات لاطار عمل الكينونة من اظهار المنتجات Products ذات التصنيف المحدد فقط Category في شبكة productDataGrid
  • من صندوق الادوات نختر الزر Button ونسحبه للنموذج ونضبط خاصية الاسم له Name علي  buttonSave  وخاصية المحتوي Content علي Save

سيبدو النموذج الان شبيها بالتالي:

اكواد التعامل مع التفاعلات مع البيانات

سنضيف الان بعض معالجات الاحداث.

  • في نافذة زامل XAML ننقر علي  العنصر <Window سيقوم هذا بتحديد النافذة الرئيسة

من نافذة الخواص Properties اختر  زر الاحداث Events من اعلي اليسار ثم انقر نقر مزدوجا علي صندوق النص  علي يمين الملصق Loaded

  • ايضا اضف الحدث Click لزر حفظ Save بالنقر مزدوجا علي زر حفظ في المصمم

ينقلك هذا لملف الشفرة المضمنة للنموذج code behind، سنعدل الشفرة الان لتستخدم ProductContext للوصول للبيانات. عدل الشفرة لتبدو كما في الاسفل

يعرف الكود المثيل طويل العمر long-running لسياق المنتج ProductContext. ويستخدم كائن ProductContext لاستعلام البيانمات وحفظها في قاعدة البيانات. ومن ثم نستدعي التحرير Dispose() للمثيل ProductContext من المنهج المتجاوز OnClosing.

using System.Linq;

using System.Windows;

using System.Data.Entity;

namespace WPFwithEFSample

{

    /// <summary>

    /// Interaction logic for MainWindow.xaml

    /// </summary>

    public partial class MainWindow : Window

    {

        private ProductContext _context = new ProductContext();

        public MainWindow()

        {

            InitializeComponent();

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            System.Windows.Data.CollectionViewSource categoryViewSource =

                ((System.Windows.Data.CollectionViewSource)(this.FindResource(“categoryViewSource”)));

            // Load  هو منهج ممتد علي IQueryable,

            //  مغرف بمجال الاسماء  System.Data.Entity

            // ويرقم هذا المنهج نتائج الاستعلام

            //وهو شبيه لمنهج ToList لكن بدون انشاء لائحة

// عند استخدامه مع  Linq2E فان هذا المنهج

            // ينشئ كائنات الكينونة ويضيفها للسياق

           // _context.Categories.Load();

            _context.Categories.Load();

            // بعد تحميل البيانات فان الخاصية المحلية لـ DbSet<T>

            // لاستخدام  DbSet<T> كمصدر ربط.

            categoryViewSource.Source = _context.Categories.Local;

        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)

        {

            base.OnClosing(e);

            this._context.Dispose();

        }

        private void btnSave_Click(object sender, RoutedEventArgs e)

        {

            // عند حذف كائن من تجميعة كينونات ذات صلة

            //(المنتجات في هذا المثال) فان اطار عمل الكينونة لايعلم

            // هذه الكينونة الابن كمحزوفة

            // لكنه يقوم بحذف العلاقة بين الام والابن

            // عبر ضبط مرجع الاب علي لاشيء null.

            // لذا علينا حذف المنتجات يدويا

            // التي لديها مرجع تصنيف مضبوط علي null.

            // الاكواد التالية تستخدم  LINQ to Objects

            // مقابل التجميعة المحلية للمنتجات

            // نداء ToList مطلوب لان بغير ذلك ستعدل التجميعة

            // بحذف الاستدعاء اثناء ترقيمه

            // في معظم الحالت الاخري يمكنك استخدام  LINQ to Objects مباشرة

            //مقابل الخاصية المحلية من دون استخدام  ToList اولا

            foreach (var product in _context.Products.Local.ToList())

            {

                if (product.Category == null)

                {

                    _context.Products.Remove(product);

                }

            }

            _context.SaveChanges();

            // Refresh the grids so the database generated values show up.

            this.categoryDataGrid.Items.Refresh();

            this.productsDataGrid.Items.Refresh();

        }

    }

}

اختبار التطبيق

  • ترجم التطبيق وشغله. اذا اخترت مقاربة الشفرة اولا فستلاحظ انه تم انشاء قاعدة بيانات WPFwithEFSample.ProductContext
    اذا كان SQL Express مثبتا لديك (مضمن مع فيجوال ستديو 2010) فسيتم انشاء قاعدة البيانات لديك في مثل خادم السيكوال المحلي SQL Express المسمي (.\SQLEXPRESS). اما في حالة 2012 فستجد القاعدة في ((localdb)\v11.0).
    ملاحظة : سيحصل SQL Express دائما علي الاسبقية مادام مثبتا علي جهازك حجتي ولو كنت تسخدم فيجوال ستديو 2012

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

  • ثم انقر علي زر حفظ لحفظ هذه البيانات بقاعدة البيانات

بعد استدعاء سياق بيانات SaveChanges()  سيتم ملء المعرفات بالقيم التي تولدها قاعدة البيانات لاننا نستدعي Refresh() بعد SaveChanges() لذا يتم تحديث التحكم DataGrid بالقيم الجديدة ايضا

المصدر بتصرف

Git

فيجوال ستديو وGitHub: اساسيات العمل مع المستودعات

git
سنغطي بعض الاساسيات لاستخدام فيجوال ستديو للعمل مع مستودعات Github موجودة مسبقا كما لو اردنا مثلا المشاركة في مشروع فيجوال ستديو موجود مسبقا علي Github
• المتطلبات
• اشتقاق المستودع Forking
• نسخ المستودع Cloning
• ايداع التغييرات علي المستودع المحلي Committing
• رفع التغييرات للمستودع البعيد Pushing
• ارسال طلب سحب Submitting Pull Requests
المتطلبات
سنستخدم فيجوال ستديو 2013 فهو يأتي بدعم مدمج لتقنية Git . فلن نحتاج لاي تنزي لمكون اضافي. اما اذا لم يكن لديك فيجوال ستديو 2013 فانصحك بتنزيله فورا وان كنت ستجد بعض الموارد التعليمية لانجاز ما سنفعله باستخدام فيجوال ستديو2012 لكن يظل 2013 هو الخيار المفضل فهو يقدم لنا دعم لانشاء تطبيقات المخزن بسهولة.
طبعا تحتاج ايضا لحساب Github. وان لم يكن لديك فيمكنك البدء بانشاءه فهو مجاني.
اشتقاق المستودع Forking a Repository
لنفترض انك وجدت مستودعا لجيت وانت مهتم بالمشاركة فيه. يمكنك ان تطلب من مالك المستودع اعطاءك بعض الصلاحيات للوصول للمستودع حتي تقوم بالتغيرات التي تريدها وتوقع ان تسمع كلمة “لا” هذا اذا رد عليك في الاساس. او يمكنك ببساطة ان تنسخ المستودع لمستودع اخر تحت حسابك في جيت لتستطيع القيام بما تحب من تغييرات في نسختك الخاصة. وهذه هي وظيفة الاشتقاق الاساسية حيث تعد لك نسخة في حساب جيت الخاص بك. كما تتيح لك طريقة للارتباط بالمستودع الذي اشتققت منه وهكذا تستطيع ادماج ما قمت به من اضافات عظيمة للمستودع الرئيس (بعد ان يوافق المالك بالطبع).
يقدم لنا Github مستودعا اسمه “Spoon-Knife” وهو متاح لاعمال التعليم وهو ماسنستعمله للتعلم في هذه المقالة. لنفترض اننا نريد القيام ببعض المساهمات في هذا المستودع. نقوم اولا بالولوج لحساب جيت الخاص بنا ثم ننتقل للمخزن “Spoon-Knife” ثم ننقر علي زر الاشتقاق Fork لاشتقاق نسخة من المستودع.

صورة
بعد ثوان ستحصل علي نسخة من المستودع في حسابك وسيصبح الرابط للمستودع يعود للمستودع الذي اشتققنا منه يظهر في الاعلي بينما رابط HTTPS clone URL يمر بحسابك وسنحتاج اليه في الخطوة التالية.
صورة
نسخ المستودع Cloning a Repository
نسخ المستودع يعني الحصول علي نسخة محلية علي جهازك وهذا يتيح لك ايداع التغييرات للمستودع المحلي في غياب أي اتصال بالمستودع البعيد علي Github (أي حتي في غياب الانترنت). وهذا هو الفرق بين نظم التحكم بالنسخ الموزعةdistributed والمركزية centralized .
من نافذة متصفح الفريقTeam Explorer في الفيجوال ستديو انقر علي زر اتصال Connect وسيعرض لك المستودعات المتاحة التي تستطيع الاتصال بها.
صورة
وبما اننا قد لانملك أي مستودع بعد فسنقوم بنسخ المستودع البعيد بالنقر علي رابط نسخ Clone.
صورة
نقوم باضافة العنوان الذي تحصلنا عليه من HTTPS clone URL في المستودع البعيد عندما اشتققناه علي حسابنا نضيفها لحقل العنوان ثم ننقر علي زر نسخ Clone الذي سيقوم بجلب نسخة منها للمستودع المحلي.
صورة
والان عندما نفتح مستعرض الفريق Team Explorer في المستقبل سنري هذا المستودع في جزء مستودعات جيت المحلية Local Git Repositories.
صورة
ماقمنا به حتي الان ليس معقدا فاذا انتقلنا لمجلد المشروع علي مستعرض الوندوز فسنجد نسخة من مشروع جيت علي الخادم البعيد موجودة لدينا. واذا دققنا النظر سنجد مجلد باسم“.git”. حيث يقوم جيت بتخزين المعلومات عن المستودع المحلي اثناء عملنا علي المشروع. طبعا علينا ان لانقوم بمسح هذا المجلد.
صورة
ايداع التغييرات في المستودع المحلي Committing Changes
اصبحنا الان جاهزين للقيام ببعض المساهمات في هذا المستودع. لنفترض انني اريد اضافة مشروع جديد. سابدأ باضافة مشروع جديد وضبط مكانه Location لمسار المستودع المحلي.

صورة
انقر علي موافق OK لانشاء المشروع في مجلد المستودع المحلي. ثم انتقل لنافذة مستعرض الفريق Team Explorer واختر التغيرات Changes …


سيتم عرض كل المجلدات والملفات لمشروعنا الجديد في التغييرات المضمنة Included Changes. وهذا لايعني انه تم ايداع هذه التغيرات. لكنه يعني ان كل من جيت وفيجول ستديو علي علم بها ويتابعان التغييرات فيه.

صورة
لايداع التغيرات نحتاج لادخال رسالة او وصف للتغيرات التي نريد ايداعها ثم ننقر علي زر ايداع Commit.

صورة
الان قمنا بايداع التغيرات للمستودع المحلي. تذكر اننا لم نقم بايداعها في الخادم البعيد علي Github بعد. سنري ذلك لاحقا


ليس من الضرور ان تأتي كل التغييرات من الفيجوال ستديو فقط. فمثلا اذا اردنا اضافة توجيهات للمستخدم للعمل مع هذا المشروع. فيمكننا ببساطة انشاء ملف علي المجلد المحلي.

صورة
لنعد الان لمستعرض الفريق Team Explorer وفي الجزء الملفات غير المتابعةUntracked Files والتي يهتم فيها فيجوال ستديو وجيت بالملف الجديد لكن لايتابعانه tracking. لنبدء بمتابعته ننقر بالزر الايمن عليه ونختر اضافة Add.

صورة
الان هذا الملف تتم مراقبته كتغير في المستودع المحلي. لكننا لم نقم بايداعه بعد للمستوع.

صورة
لايداع هذا التغير سنضيف تعليقا ثم ننقر علي زر ايداع Commit كما شرحنا سابقا.
حتي الان فقد قمنا بايداعين للمستودع المحلي. يمكننا رؤية هذه الايداعات وتفصيلات كل منها بالنقر علي رابط ايداعات Commits.

صورة
سنجد الايداعين في قسم ايداعات صادرة Outgoing Commits. حيث نستطيع النقر مزدوجا علي الايداع لرؤية تفاصيله.

صورة
بعدها يمكننا النقر علي مزامنة Sync وسيخبرنا بنجاحه بالرسالة التالية

صورة
لنراجع الملفات غير المراقبة Untracked Files.
تفترض الاداة انك لاتريد اضافة هذه الملفات لمتحكم النسخ. فعموما انت تحتاج للشفرة المصدرية فقط في المستودع وليس عمل المترجم الموجود في المسار bin\Debug و obj\Debug. ولاتريد ايداع ملف خيارات المستخدم لبيئة فيجوال ستديو ايضا للمستودع. يمكنك اخبار جيت ان يتجاهل هذه الملفات بالنقر بالزر الايمن عليها ثم اختيار تجاهل ignore. وسيظهر لنا ملف .gitignore في مجلد المستودع المحلي خيث سيتم تجاهل كل ما اضفناه هنا ولن يتم ايداعه في المرات القادمة.


لدينا ايضا الخيار في مسح الملفات غير المتابعة Untracked. وسيتم مسحها فعليا من المستودع الموجود علي القرص لدينا. وعلي كل حال في المرة التالية عندما تقوم ببناء التطبيق build فسيتم اعادة انشاء وعرض النسخ الاحتياطية كملفات غير متابعة.
رفع التغيرات للمستودع البعيد Pushing Changes
في النهاية يجب ان نرفع التغييرات التي قمنا بها من المستودع المحلي للمستودع البعيد علي Github. وهي وظيفة الرفع push. عندما تهيئ عملية الرفع فانه يتم التحقق من مستودعك المحلي مقابل المستودع البعيد ليتأكد مما اذا كان هناك تغييرات تمت وليست لديك علي المستوددع المحلي. واذا كان الامر كذلك فعليك ان تقوم بحل التضاربات الناشئة محليا قبل ان تدفع بتغييراتك انت للمستودع البعيد. وبما ان المستودع في مثالنا يعود لنا فقط ولايوجد مشترك اخر معنا فلا نتوقع أي تغييرات في المستودع البعيد مما يعني ان مشروعنا في المستودع المحلي سيكون دائما متزامنا مع اخر التغييرات في المستودع البعيد.
باستخدام مستعرض الفريق يمكنك جلب Fetch او رفع سحب Pull الايداعات من المستودع البعيد. الجلب سيحضر لنا لائحة بالايداعات بدون تطبيق التغييرات علي المستودع المحلي. مما يعطينا فرصة لمراجعة التغييرات المحدثة من قبل المستخدمين الاخرين قبل ان نتابع. اما السحب Pull فسيقوم بتطبيق التغييرات في المستودع البعيد علي مستودعنا المحلي، وهو ما سيدفعنا لمعالجة أي تضارب قد يحدث.

صورة
وحالما يكون المستودع المحالة في حالة مزامنة sync مع المستودع البعيد. ننقر علي رابط رفع Push في قسم التغيرات الصادرة Outgoing Commits لنقوم برفع التغييرات التي انشأناها للمستودع البعيد. وعندما ينتهي الرفع ستصبح كل من التغييرات الصادرة Incoming Commits والتغيرات الواردة Outgoing Commits خاليتان. مما يعني ان كل من المستودع المحلي والمستودع البعيد متزامنان.

صورة
واذا عدنا الان للمستودع في Github فسنري هذه الايداعات قد تم تطبيقها.

صورة
في اعلي الصفحة هناك رابط الايداعات commits . الدخول فيه سيظهر لنا تفاصيل هذه الايداعات. وفي صفحة الايداعات يمكنك الانتقال للتغييرات لتري أي ملفات اضيفت او عدلت.

صورة
ارسال طلب سحب Submitting Pull Requests
كل التغييرات التي قمنا بها حتي الان تمت في مستودعاتنا سواء في المستودع المحلي او البعيد الذي اشتققناه من المستودع “octocat/Spoon-Knife”. لنفترض الان انني اريد ان اعرض هذه التغييرات التي انشأتها علي مالك المستودع octocat/Spoon-Knife. يتم هذا عبر طلب السحب Pull Request. وهو عبارة عن طلب من مالك المستودع الاصلي ان يسحب التغييرات التي قمنا بها الي مستودعه الاصلي. اذا قبل فستصبح اضافاتنا جزء من المستودع الاصلي الذي اشتقننا منه. ومستقبلا اذا اشتقننا نحن او أي احد اخر من المستودع octocat/Spoon-Knife فستكون مساهمتنا مضمنة.
لارسال طلب سحب. سننقر علي رابط Pull Requests علي الجانب الايمن من الشاشة.

صورة
وسينقلنا هذا لشاشة حيث نستطيع رؤية كل طلبات السحب التي قمنا بها. وبما انه اول طلب سحب لنا فلن يظهر لنا شيء. ننقر علي الزر طلب سحب جديد New pull request.

صورة
ينقلنا هذا لشاشة اخري تعرض لنا تفاصيل الطلب الذي نريد ارساله.

صورة
وحالما نؤكد ان هذا هو مانريده بالضغط علي رابط Click to create a pull request for this comparison. سينقلنا لشاشة تمكننا من ادخال عنوان وتعليق مختصر لطلب السحب.


انقر علي زر ارسال طلب السحب Create pull request لارسال الطلب وسيعيدنا مباشرة للمستودع الاصلي octocat/Spoon-Knife. وهذا كل ما في الموضوع.

صورة
اعتبارات قبل ارسال طلب السحب
اذا كنت مساهما جديدا في المستودع فقد تكون في حوجة لاستعراض طلبات السحب للمستودع الاصلي الذي اشتققت منه ويمكنك ذلك بالذهاب للمستودع في Github.

صورة
ثم اختيار الرابط Pull Requests ليمين الشاشة. وسينقلك لصفحة تعرض كل طلبات السحب التي ارسلت لمالك هذا المستودع. ومن هنا يمكنك معرفة انشط المساهمين ونوعية طلبات السحب التي قبلها مالك المستودع. وهذا سيعطيك رؤية لمقاييس التشفير المتوقع منك اتباعها. مثلا هل عليك استخدام الحروف الكبيرة لاسماء المتغيرات UPPERCASE أم انه يتوقع من استخدام حالة الجملcamelCase مما يعني انك غالب ما ستستقبل بعض التعليقات من المالك بخصوص تغيير هذه الاشياء قبل ان يقبل بسحب تغييراتك لمستودعه.
الخلاصة
هناك الكثير مما لم نتطرق اليه كالتفريع branching ومراجعة الايداعات reverting commits الخ. قد نتناولها في مقالة اخري فقد غطينا هنا الاساسيات فقط.
هناك الكثير من المستندات الجيدة لتعلم جيت Git و Github ولمعرفة الاختلافات بين نظم ادارة النسخ سواء كانت الموزعة أوالمركزية منها. يمكنك البحث في غوغل وان كنت ساقدم لكم هذا الرابط المفيد من موقع ميكروسوفت.
اعدت هذه المقالة لموقع جيت بالعربية
مترجم بتصرف

نثريات

القصيدة تفوح عطرا


القصيدة مخلوق كامل التخلق.
ينبغي ان نعيد النظر في نظرتنا للمخلوقات. فهذه الحروف الصغيرة المتقافزة. طفولية الوجه وصباحية المحيا حينما نقرأها تعيدنا كمركبة الزمن للحظات نادرة ظننا اننا نسيناها.
وتعود نذكر كل شيء كأنا ما نسينا. كأننا الان في ذبابة السيف والدموع هي الدموع وكأن هريرة لم تغادر. وكأن الاعشي شاهدا يمد لسانه.
مع هذه الذكري اقدم اليوم ثلاث قصائد علي انفض الغبار عن شاعر كان
يومان ثم ستشرق الدنيا
جريمة الحب
للحبيبة واحتراق الامنيات

قصائدي, أشعار

جريمة الحب


ارتكبت جريمة الحب
واقترفت جريرة الغفران
ارتكبت جريمة النسيان
وارتكبت جريمة الاحزان
وانا الان تغطيني ذنوبي
من شمالي لجنوبي
ليس من صلب ولا رجم يطهرني
ولا انسان
وانا الذي اقسمت في الايمان احيا
واموت بالإيمان
لا الدغ من تفس المكان
والان …. ماذا الان؟
الان يا سيدي
خوف ارتحالك هدّ معصم الاشجان
عجبا !!!
بنفسك تبني سجن قلبك
ثم تبكي زرقتان
فاختر سماؤك لونه
واختر محيطك مرتان
قسما سَتَغْرَقُ او سَتُغْرَقُ
أو ستُعزَلُ قبل تعتزل الرهان
ابكي اختيارك في انكسارك
واعتزل غصص الاسي
واحترق عبق المكان
المم شذاك الي انوف الناس … فح
ليس الاريج ابن المكان
خضت في العشر الخطايا
ثم ترجو زورق الاحزان
ترجو ان ستدرك مرة بر الامان
انت ارتكبت جريمة الغفران

قصائدي, أشعار

يومان ثم ستشرق الدنيا

هذا احتراقك في انتظارك
هذا ازارك
ماذا تقول اذا اتاك صباحك الوردي زارك
ثم في نزق تمطي
عبق الاركان غطي كل دارك
فاسمع الي الخطو الهزيمي الصرير
طرق ببابك
يومسن
يومان يا سيدي ويأتيك النهار
شيء حبيب
تبكي وتلعن كل ذرات الغبار
وجع غريب
وجع غريب
هذا الذي أرخي عنان الشوق عندك
دون مملكة الوقار
صلي واغفي ثم يا سيدي استدار
مازال اسم الشوق شوق
واسم النار نار
مازال اسم الوجد وجد
واحتراق القلب حار
لا لم يغير في معاني الحب
غيبة شخصك الملكي لم يأتي النهار
فالفظ قرارك في انكسارك
أو توكل قبلة الاحزان دار
هذا فؤادك غاب اسبوع وعاد
غاب شهر. . . غاب حول
غاب دهر . . . فر طار
فانسي اذا ما شئت ان تنسي
وسافر دون ان تستأذن الانهار
يوم ويأتي في قشيب الشوق
يسحب الف عذر
سامح . . . فؤادك جوهرا أو عقد در
سامح . . . بقاءك في خليج الحزن مر
سامح . . . فما يأتي كما تدري يسر
سامح . . . فان الصير قر
يوما ويأتي الورد
يورق في فؤادك زورقان من الحنان
تنسي واني واثق ان سوف تنسي ما استبان
حتما تفتش الف عذر
حتما ستختصر الزمان:
“هي بضع ايام وما قد كان كان”