تحديث 29-05-2020 سأقوم برفع الشفرة المصدرية لنظام الحجوزات على القيت هب هنا
دوت نت كور تقنية جديدة من مايكروسوفت تم إصدارها في 2015 وتم كتابة شفرتها من الصفر بحيث أنها لا تقوم بالإعتماد على الـ DotNet Framwork. مميزات الدوت نت كور عديدة جدا ومن أهمها أنها تعتبر Cross platform بحيث يمكن تشغيلها على معظم أنظمة التشغيل ومن أهمها نظام التشغيل لينكس والماك. لا أريد أن أطيل في الشرح عن ماهي الدوت نت كور… بقدر ما سنقوم بعرض أمثلة عديدة تساعدنا على طريقة عمل التقنية.
سنقوم بإنشاء تطبيق حجوزات بسيط يوضح لنا مميزات التقنية…
الأدوات التي ستحتاجها
Visual Studio 2019
SQL Server 2016
MogoDB
بالنسبة لـ mongoDB سأقوم بعمل صورة عملية متكاملة عنها وسأقوم بإنشاء نمط التصميم المستودعي Repository Pattern والذي سيتم معها.. لكن لن أقوم بإستخدامها في عملية حفظ وحجز التذاكر… لأنني سأقوم بإستخدام الـ Sql Provider لهذه العملية… لكن بإمكانك إستخدام الـ MongoDB إن أردت لأن نمط التصميم سيكون جاهز
لماذا MongoDB؟ المشروع الذي ستعمل عليه (أنت كقارئ / قارئة) هو نموذج مبسط من مشروع ضخم آخرونسبة لأن تدفق المعلومات في مثل هذه المشاريع دائما مايكون كبيرا بالتالي ستحتاج للسرعة في نقل وإرجاع البيانات و قواعد البيانات المفهرسة تعتبر أفضل من هذه الناحية.
سأقوم بالتركيز في هذه المقالة على فئتين تعتبران محور عمل الدوت نت كور
Program.cs
Statup.cs
حسنا؛ لقد قمنا بتوضيح ما سنقوم به.. الآن قم بفتح الفيجوال ستدويو قم بإنشاء Blank solution جديد وقم بإعطاءه الاسم Reservation_Sys قم بإنشاء 4 مكتبات للفئات بالاسماء التالية…ولا تنسى بأن تقوم بإختيار الدوت نت كور كـقاعدة عمل
Reservation_Sys.Infrastructure
Reservation_Sys.Model
Reservation_Sys.Service
Reservation_Sys.Repository
قم بإنشاء تطبيق ASP.NET Web Application من النوع Empty ولا تنسى ان يكون الدوت نت كور كقاعدة عمل… وقم بإعطاءه الاسم التالي:
Reservation_Sys.Web.UI.MVC وقم بربطه مع الـ Reservation_Sys.Model و Reservation_Sys.Service و Reservation_Sys.Repository
قم بعملية ربط للـ Reservation_Sys.Service مع الـ Reservation_Sys.Model و Reservation_Sys.Repository
قم بعملية ربط للـ Reservation_Sys.Repository مع الـ Reservation_Sys.Service و Reservation_Sys.Model
قم بإنشاء مجلدين داخل مشروع الـ Reservation_Sys.Model الأول بإسم Entities والآخر بإسم SqlServerData
لا تقلق عزيزي القارئ؛ سأقوم بشرح مفصل لكل شئ قمت بإنشاءه سابقا.. فقط نريد أن نقوم بتهيئة المشروع في البداية، وبعدها سنقوم بالشرح بالتفصيل مع التحليل قبل إنشاء الفئات التي سنعمل عليها.
بالنسبة لمشروع الـ MongoDB سيكون على الـ Github وذلك نسبة لحجم المساحة هنا.
ملاحظة: مرة أخرى سأقوم بشرح وتحليل المشروع بعد الانتهاء من تهيئة جميع أجزاء الـ Model
سأقوم بإنشاء الفئات وربط الفئات مع بعضها البعض Relationship وسأقوم بإستخدام الـ EF Code First والتي ستمكنني من إنشاء قاعة البيانات عن طيقة خاصية الـ Migration
داخل المجلد Entities قم بإنشاء الفئات التالية واحدا تلو الآخر
namespace Reservation_Sys.Model.Entities
{
public class Bus
{
public int BusID { get; set; }
public string DriverName { get; set; }
public int No_OfSeat { get; set; }
public DateTime AddedDate { get; set; }
public string AddedBy { get; set; }
public virtual ICollection<ScheduleTrip> ScheduleTrips { get; set; }
}
}
namespace Reservation_Sys.Model.Entities
{
public class City
{
public int CityID { get; set; }
public string Name { get; set; }
public DateTime AddedDate { get; set; }
public string AddedBy { get; set; }
}
}
namespace Reservation_Sys.Model.Entities
{
public class ScheduleTrip
{
public int ScheduleTripID { get; set; }
public int BusID { get; set; }
public string FromCity { get; set; }
public string ToCity { get; set; }
// We can build any schema fro generate tripcode,
// but instead i will use hard type
public string TripCode { get; set; }
public string FromLandPort { get; set; }
public string ToLandPort { get; set; }
public decimal TripAmount { get; set; }
public DateTime DepartureTime { get; set; }
public DateTime ArrivalTime { get; set; }
public string AddedBy { get; set; }
public DateTime AddedDate { get; set; }
public virtual Bus Bus { get; set; }
public virtual ICollection<Reservation> Reservations { get; set; }
}
}
namespace Reservation_Sys.Model.Entities
{
public class Reservation
{
public int ReservationID { get; set; }
public int ScheduleTripID { get; set; }
public string ClientIdentityNo { get; set; }
public string ClientName { get; set; }
public string PayType { get; set; }
public string CreditCardNo { get; set; }
public DateTime ExpiryDate { get; set; }
public int SeateNo { get; set; }
public string AddedBy { get; set; }
public DateTime AddedDate { get; set; }
public virtual ScheduleTrip ScheduleTrip { get; set; }
public virtual ICollection<Booking> Bookings { get; set; }
}
}
namespace Reservation_Sys.Model.Entities
{
public class Booking
{
public int BookingID { get; set; }
public int ReservationID { get; set; }
public bool Status { get; set; }
public virtual Reservation Reservation { get; set; }
}
}
حسنا الآن قمنا بإنشاء جميع الفئات التي ستساعدنا في جميع مراحل عمل التطبيق… من الضروري تنزيل مكتبة الـ Entity Framework Core على مشروع الـ Model لأننا سنقوم بإستخدام الفئة DbContext في جميع العمليات التي ستتم على قاعدة البيانات.
حسنا.. سننتقل لمرحلة أخرى وهي مرحلة العمل على إنشاء جداول قاعدة البيانات، سأقوم بإستخدام طريقة الـ Fluent API والتي تتيح لي إستخدام لغة الـ #C في إنشاء فئات وبها سأقوم بعمل جيمع أنواع البيانات بالنسبة لقاعدة البيانات SQL Server مع جميع أنواع الـ Constraint التي سأحتاجها في قاعدة البيانات… قم بإنشاء جميع الفئات التالية واحدة تلو الأخرى داخل المجلد SqlServerData.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Reservation_Sys.Model.Entities;
namespace Reservation_Sys.Model.SqlServerData
{
internal class BusSchemaMap : IEntityTypeConfiguration<Bus>
{
public void Configure(EntityTypeBuilder<Bus> builder)
{
builder.ToTable("Buses", "dbo");
builder.HasKey(k => k.BusID);
builder.Property(p => p.AddedBy).HasMaxLength(50).IsRequired(true);
builder.Property(p => p.AddedDate).IsRequired(true).HasDefaultValue(DateTime.Now);
builder.Property(p => p.DriverName).IsRequired(true).HasMaxLength(200);
builder.Property(p => p.No_OfSeat).IsRequired(true).HasMaxLength(50);
}
}
}
لن أوقم مرة أخرى بإدارة فضاءات الأسماء في الفئات المتبقية، فقط سأقوم بإدراج اسم الفئة.. نسبة لضيق المساحة وكسبا للوقت.
internal class CitySchemaMap : IEntityTypeConfiguration<City>
{
public void Configure(EntityTypeBuilder<City> builder)
{
builder.ToTable("Cities", "dbo");
builder.HasKey(k => k.CityID);
builder.Property(p => p.AddedBy).IsRequired(true).HasMaxLength(200);
builder.Property(p => p.AddedDate).IsRequired(true).HasDefaultValue(DateTime.Now);
builder.Property(p => p.Name).IsRequired(true).HasMaxLength(40);
}
}
internal class ScheduleTripSchemaMap : IEntityTypeConfiguration<ScheduleTrip>
{
public void Configure(EntityTypeBuilder<ScheduleTrip> builder)
{
builder.ToTable("ScheduleTrips", "dbo");
builder.HasKey(k => k.ScheduleTripID);
builder.Property(p => p.ArrivalTime).IsRequired(true);
builder.Property(p => p.DepartureTime).IsRequired(true);
builder.Property(p => p.FromCity).IsRequired(true);
builder.Property(p => p.FromLandPort).IsRequired(true);
builder.Property(p => p.ToCity).IsRequired(true);
builder.Property(p => p.ToLandPort).IsRequired(true);
builder.Property(p => p.TripAmount).IsRequired(true);
builder.Property(p => p.TripCode).IsRequired(true);
builder.Property(p => p.AddedBy).IsRequired(true);
builder.Property(p => p.AddedDate).IsRequired(true).HasDefaultValue(DateTime.Now);
builder.HasOne(p => p.Bus)
.WithMany(m => m.ScheduleTrips)
.HasForeignKey(f => f.BusID);
}
}
internal class ReservationSchemaMap : IEntityTypeConfiguration<Reservation>
{
public void Configure(EntityTypeBuilder<Reservation> builder)
{
builder.ToTable("Reservations", "dbo");
builder.HasKey(k => k.ReservationID);
builder.Property(p => p.ClientIdentityNo).IsRequired(true).HasMaxLength(20);
builder.Property(p => p.ClientName).IsRequired(true).HasMaxLength(200);
builder.Property(p => p.CreditCardNo).IsRequired(false).HasMaxLength(20);
builder.Property(p => p.ExpiryDate).IsRequired(true);
builder.Property(p => p.PayType).IsRequired(false);
builder.Property(p => p.SeateNo).IsRequired(true);
builder.Property(p => p.AddedDate).IsRequired(true).HasDefaultValue(DateTime.Now);
builder.Property(p => p.AddedBy).IsRequired(true);
builder.HasOne(p => p.ScheduleTrip)
.WithMany(m => m.Reservations)
.HasForeignKey(f => f.ScheduleTripID);
}
}
internal class BookingSchemaMap : IEntityTypeConfiguration<Booking>
{
public void Configure(EntityTypeBuilder<Booking> builder)
{
builder.ToTable("Bookings", "dbo");
builder.HasKey(k => k.BookingID);
builder.Property(p => p.Status).IsRequired(true);
builder.HasOne(p => p.Reservation)
.WithMany(m => m.Bookings)
.HasForeignKey(f => f.ReservationID).IsRequired(true);
}
}
لاحظ أن جميع أنواع الوصول لهذه الفئات هي internal وذلك لأنني لن أقوم بإستخدامها خارج مكتبة الفئات Model، فسأقوم بإستخدامها داخل الفئة ReservationContext وهي الفئة التي تقوم بعمل جميع الحركات التي ستتم على قاعدة البيانات وأيضا تقوم بإنشاء جميع الجداول في قاعدة البيانات… الآن قم بإنشاء فئة جديدة داخل المجلد Entities وقم بإعطاء هذه الفئة اسم ReservationContext كما مبين تاليا
public class ReservationContext : DbContext
{
public ReservationContext() { }
public ReservationContext(DbContextOptions<ReservationContext> options) : base(options)
{
}
public DbSet<Booking> Bookings { get; set; }
public DbSet<Bus> Buses { get; set; }
public DbSet<City> Cities { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<ScheduleTrip> ScheduleTrips { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new BookingSchemaMap());
modelBuilder.ApplyConfiguration(new BusSchemaMap());
modelBuilder.ApplyConfiguration(new CitySchemaMap());
modelBuilder.ApplyConfiguration(new ReservationSchemaMap());
modelBuilder.ApplyConfiguration(new ScheduleTripSchemaMap());
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies(true);
}
}
قم بتنزيل المكتبة Microsoft.EntityFrameworkCore.Proxies من على الـ NeGet. وهي المكتبة التي ستساعدنا في عمل الإستعلام بالنسبة لجميع العمليات التي تقوم بجلب البيانات من أكثر من جدول Lazy Loading.
داخل مشروع الـ Infrastructure قم بإنشاء الواجهة التالية:
public interface IDateTime
{
DateTime Now { get; }
}
هذه الواجهة ستساعدنا في عمليه جلب الوقت من خلال استخدام الـ DI وذلك لان الفئة DateTime لديها خاصية Now وهي عبارة عن static بالتالي سأقوم بإستخدام الـ Adapter Design Pattern … ستفيدك هذه الفئة إذا كنت ستقوم بإستخدام كتابة شفرات الإختبار Unit Testing وذلك لأن الـ DateTime classs لا نسطيع السيطرة عليه نسبة لأه يعمل أثناء الـ Rum-time وإستخدامنا للـ Adapter Design Pattern بإمكاننا عمل مثيل للفئة من خلال الواجهة Interface التي قمنا بأنشائها IDateTime.
الآن قم بإستخدام فئة جديدة بإسم DateTimeAdapter وجعلها ترث من الـواجهة IDateTime.
public class DateTimeAdapter : IDateTime
{
public DateTime Now
{
get { return DateTime.Now; }
}
}
حسنا الآن جميع الأساسيات التي يحتاجها التطبيق من مشروع الـ Model جاهز للعمل في المقالة الثانية سنقوم بإلقاء نظرة على مشروع الـ Repository وأيضا في حال إحتجنا لعمل أي تعديل في مشروع الـ Model أو الـ Infrastructure سنقوم به.
وكما ذكرت في بداية هذه المقالة أن تركيزي سينصب نحو عمل الدوت نت كور وليس طريقة إنشاء الفئات وطريقة عمل أنماط التصميم. فبالتالي سأمضي سريعا في عملية إنشاء مكتبات الفئات الأخرى. لكن سأِرح بالتفصيل عملية عمل مشروع ال Web.
أريد فكرة مشروع بيه صور وصوت وفيديو (وسائط)
[…] – منحنيات بيزييه” من مدونة المحلل العربي، و”نظرة على DotNet Core من خلال تصميم نظام حجوزات” من مدونة […]
هذ أفضل تجربة سأجربه في عمري
أريدو ان تنجح هذه المرة)لأني فشلة في مرة سبقاة أريدو أيض ذهب إلى ريال مدريد في دوري إسباني