This article introduces you to the in-browser document database known as IndexedDB. With IndexedDB you can create, read, update, and delete large sets of records in much the same way you are accustomed to doing with server-side databases. To experiment with a working version of the code presented in this article, please go to , and the full source code is available via the GitHub repository found at .
غروب log4net
As of April 1, 2020 Log4Net is a dormant project of Apache Logging Services. The dormant status means the project has been classified as inactive since it has had no recent development activity and there are no active volunteers to perform code reviews, commit code, or perform releases. Although it is possible volunteers might choose to participate in the future, it is best to assume there will be not future development or releases.
5 JavaScript Security Best Practices for 2024
Any JavaScript web application needs to have a Content Security Policy (CSP), a browser security standard that dictates what the browser is allowed to load — whether that be a domain, subdomain, or resource. Without a CSP, hackers can exploit cross-site scripting vulnerabilities, potentially resulting in a data breach.
بررسی Blazor United در دات نت 8
تزریق وابستگیها در Typescript
InversifyJS is a lightweight inversion of control (IoC) container for TypeScript and JavaScript apps. A IoC container uses a class constructor to identify and inject its dependencies. InversifyJS has a friendly API and encourage the usage of the best OOP and IoC practices.
If you haven’t tried Xamarin yet, now is the time! Read this free white paper from Syncfusion to learn how Xamarin can improve your cross-platform development:
- Deliver apps faster by sharing code across platforms, using one code base and UI.
- Use best-in-class development tools, like Visual Studio.
- Produce genuine native apps that don’t compromise the end user experience.
- And more!
Globalization در ASP.NET MVC - قسمت هفتم
با تشکر از زحمات شما.
یک بهبود جزئی: مطابق Managed Threading Best Practices بهتره از lock this استفاده نشه و از یک شیء object خصوصی استفاده شود.
Use caution when locking on instances, for example lock(this) in C# or SyncLock(Me) in Visual Basic.
If other code in your application, external to the type, takes a lock on the object, deadlocks could occur.
Data architecture is an area in which the optimal degree of isolation for a SaaS application can vary significantly depending on technical and business considerations. Experienced data architects are used to considering a broad spectrum of choices when designing an architecture to meet a specific set of challenges, and SaaS is certainly no exception. We shall examine three broad approaches, each of which lies at a different location in the continuum between isolation and sharing
EF Code First #7
مدیریت روابط بین جداول در EF Code first به کمک Fluent API
EF Code first بجای اتلاف وقت شما با نوشتن فایلهای XML تهیه نگاشتها یا تنظیم آنها با کد، رویه Convention over configuration را پیشنهاد میدهد. همین رویه، جهت مدیریت روابط بین جداول نیز برقرار است. روابط one-to-one، one-to-many، many-to-many و موارد دیگر را بدون یک سطر تنظیم اضافی، صرفا بر اساس یک سری قراردادهای توکار میتواند تشخیص داده و اعمال کند. عموما زمانی نیاز به تنظیمات دستی وجود خواهد داشت که قراردادهای توکار رعایت نشوند و یا برای مثال قرار است با یک بانک اطلاعاتی قدیمی از پیش موجود کار کنیم.
مفاهیمی به نامهای Principal و Dependent
در EF Code first از یک سری واژههای خاص جهت بیان ابتدا و انتهای روابط استفاده شده است که عدم آشنایی با آنها درک خطاهای حاصل را مشکل میکند:
الف) Principal : طرفی از رابطه است که ابتدا در بانک اطلاعاتی ذخیره خواهد شد.
ب) Dependent : طرفی از رابطه است که پس از ثبت Principal در بانک اطلاعاتی ذخیره میشود.
Principal میتواند بدون نیاز به Dependent وجود داشته باشد. وجود Dependent بدون Principal ممکن نیست زیرا ارتباط بین این دو توسط یک کلید خارجی تعریف میشود.
کدهای مثال مدیریت روابط بین جداول
در دنیای واقعی، همهی مثالها به مدل بلاگ و مطالب آن ختم نمیشوند. به همین جهت نیاز است یک مدل نسبتا پیچیدهتر را در اینجا بررسی کنیم. در ادامه کدهای کامل مثال جاری را مشاهده خواهید کرد:
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
public int Id { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
public virtual AlimentaryHabits AlimentaryHabits { set; get; }
public virtual ICollection<CustomerAlias> Aliases { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual Address Address { get; set; }
}
}
namespace EF_Sample35.Models
{
public class CustomerAlias
{
public int Id { get; set; }
public string Aka { get; set; }
public virtual Customer Customer { get; set; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Role
{
public int Id { set; get; }
public string Name { set; get; }
public virtual ICollection<Customer> Customers { set; get; }
}
}
namespace EF_Sample35.Models
{
public class AlimentaryHabits
{
public int Id { get; set; }
public bool LikesPasta { get; set; }
public bool LikesPizza { get; set; }
public int AverageDailyCalories { get; set; }
public virtual Customer Customer { get; set; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Address
{
public int Id { set; get; }
public string City { set; get; }
public string StreetAddress { set; get; }
public string PostalCode { set; get; }
public virtual ICollection<Customer> Customers { set; get; }
}
}
همچنین تعاریف نگاشتهای برنامه نیز مطابق کدهای زیر است:
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerAliasConfig : EntityTypeConfiguration<CustomerAlias>
{
public CustomerAliasConfig()
{
// one-to-many
this.HasRequired(x => x.Customer)
.WithMany(x => x.Aliases)
.WillCascadeOnDelete();
}
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// one-to-one
this.HasOptional(x => x.AlimentaryHabits)
.WithRequired(x => x.Customer)
.WillCascadeOnDelete();
// many-to-many
this.HasMany(p => p.Roles)
.WithMany(t => t.Customers)
.Map(mc =>
{
mc.ToTable("RolesJoinCustomers");
mc.MapLeftKey("RoleId");
mc.MapRightKey("CustomerId");
});
// many-to-one
this.HasOptional(x => x.Address)
.WithMany(x => x.Customers)
.WillCascadeOnDelete();
}
}
}
به همراه Context زیر:
using System.Data.Entity;
using System.Data.Entity.Migrations;
using EF_Sample35.Mappings;
using EF_Sample35.Models;
namespace EF_Sample35.DataLayer
{
public class Sample35Context : DbContext
{
public DbSet<AlimentaryHabits> AlimentaryHabits { set; get; }
public DbSet<Customer> Customers { set; get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerConfig());
modelBuilder.Configurations.Add(new CustomerAliasConfig());
base.OnModelCreating(modelBuilder);
}
}
public class Configuration : DbMigrationsConfiguration<Sample35Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(Sample35Context context)
{
base.Seed(context);
}
}
}
که نهایتا منجر به تولید چنین ساختاری در بانک اطلاعاتی میگردد:
توضیحات کامل کدهای فوق:
تنظیمات روابط one-to-one و یا one-to-zero
زمانیکه رابطهای 0..1 و یا 1..1 است، مطابق قراردادهای توکار EF Code first تنها کافی است یک navigation property را که بیانگر ارجاعی است به شیء دیگر، تعریف کنیم (در هر دو طرف رابطه).
برای مثال در مدلهای فوق یک مشتری که در حین ثبت اطلاعات اصلی او، «ممکن است» اطلاعات جانبی دیگری (AlimentaryHabits) نیز از او تنها در طی یک رکورد، دریافت شود. قصد هم نداریم یک ComplexType را تعریف کنیم. نیاز است جدول AlimentaryHabits جداگانه وجود داشته باشد.
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual AlimentaryHabits AlimentaryHabits { set; get; }
}
}
namespace EF_Sample35.Models
{
public class AlimentaryHabits
{
// ...
public virtual Customer Customer { get; set; }
}
}
در اینجا خواص virtual تعریف شده در دو طرف رابطه، به EF خواهد گفت که رابطهای، 1:1 برقرار است. در این حالت اگر برنامه را اجرا کنیم، به خطای زیر برخواهیم خورد:
Unable to determine the principal end of an association between
the types 'EF_Sample35.Models.Customer' and 'EF_Sample35.Models.AlimentaryHabits'.
The principal end of this association must be explicitly configured using either
the relationship fluent API or data annotations.
EF تشخیص داده است که رابطه 1:1 برقرار است؛ اما با قاطعیت نمیتواند طرف Principal را تعیین کند. بنابراین باید اندکی به او کمک کرد:
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// one-to-one
this.HasOptional(x => x.AlimentaryHabits)
.WithRequired(x => x.Customer)
.WillCascadeOnDelete();
}
}
}
همانطور که ملاحظه میکنید در اینجا توسط متد WithRequired طرف Principal و توسط متد HasOptional، طرف Dependent تعیین شده است. به این ترتیب EF میتوان یک رابطه 1:1 را تشکیل دهید.
توسط متد WillCascadeOnDelete هم مشخص میکنیم که اگر Principal حذف شد، لطفا Dependent را به صورت خودکار حذف کن.
توضیحات ساختار جداول تشکیل شده:
هر دو جدول با همان خواص اصلی که در دو کلاس وجود دارند، تشکیل شدهاند.
فیلد Id جدول AlimentaryHabits اینبار دیگر Identity نیست. اگر به تعریف قید FK_AlimentaryHabits_Customers_Id دقت کنیم، در اینجا مشخص است که فیلد Id جدول AlimentaryHabits، به فیلد Id جدول مشتریها متصل شده است (یعنی در آن واحد هم primary key است و هم foreign key). به همین جهت به این روش one-to-one association with shared primary key هم گفته میشود (کلید اصلی جدول مشتری با جدول AlimentaryHabits به اشتراک گذاشته شده است).
تنظیمات روابط one-to-many
برای مثال همان مشتری فوق را درنظر بگیرید که دارای تعدادی نام مستعار است:
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual ICollection<CustomerAlias> Aliases { get; set; }
}
}
namespace EF_Sample35.Models
{
public class CustomerAlias
{
// ...
public virtual Customer Customer { get; set; }
}
}
همین میزان تنظیم کفایت میکند و نیازی به استفاده از Fluent API برای معرفی روابط نیست.
در طرف Principal، یک مجموعه یا لیستی از Dependent وجود دارد. در Dependent هم یک navigation property معرف طرف Principal اضافه شده است.
جدول CustomerAlias اضافه شده، توسط یک کلید خارجی به جدول مشتری مرتبط میشود.
سؤال: اگر در اینجا نیز بخواهیم CascadeOnDelete را اعمال کنیم، چه باید کرد؟
پاسخ: جهت سفارشی سازی نحوه تعاریف روابط حتما نیاز به استفاده از Fluent API به نحو زیر میباشد:
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerAliasConfig : EntityTypeConfiguration<CustomerAlias>
{
public CustomerAliasConfig()
{
// one-to-many
this.HasRequired(x => x.Customer)
.WithMany(x => x.Aliases)
.WillCascadeOnDelete();
}
}
}
اینکار را باید در کلاس تنظیمات CustomerAlias انجام داد تا بتوان Principal را توسط متد HasRequired به Customer و سپس dependent را به کمک متد WithMany مشخص کرد. در ادامه میتوان متد WillCascadeOnDelete یا هر تنظیم سفارشی دیگری را نیز اعمال نمود.
متد HasRequired سبب خواهد شد فیلد Customer_Id، به صورت not null در سمت بانک اطلاعاتی تعریف شود؛ متد HasOptional عکس آن است.
تنظیمات روابط many-to-many
برای تنظیم روابط many-to-many تنها کافی است دو سر رابطه ارجاعاتی را به یکدیگر توسط یک لیست یا مجموعه داشته باشند:
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Role
{
// ...
public virtual ICollection<Customer> Customers { set; get; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual ICollection<Role> Roles { get; set; }
}
}
همانطور که مشاهده میکنید، یک مشتری میتواند چندین نقش داشته باشد و هر نقش میتواند به چندین مشتری منتسب شود.
اگر برنامه را به این ترتیب اجرا کنیم، به صورت خودکار یک رابطه many-to-many تشکیل خواهد شد (بدون نیاز به تنظیمات نگاشتهای آن). نکته جالب آن تشکیل خودکار جدول ارتباط دهنده واسط یا اصطلاحا join-table میباشد:
CREATE TABLE [dbo].[RolesJoinCustomers](
[RoleId] [int] NOT NULL,
[CustomerId] [int] NOT NULL,
)
سؤال: نامهای خودکار استفاده شده را میخواهیم تغییر دهیم. چکار باید کرد؟
پاسخ: اگر بانک اطلاعاتی برای بار اول است که توسط این روش تولید میشود شاید این پیش فرضها اهمیتی نداشته باشد و نسبتا هم مناسب هستند. اما اگر قرار باشد از یک بانک اطلاعاتی موجود که امکان تغییر نام فیلدها و جداول آن وجود ندارد استفاده کنیم، نیاز به سفارشی سازی تعاریف نگاشتها به کمک Fluent API خواهیم داشت:
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// many-to-many
this.HasMany(p => p.Roles)
.WithMany(t => t.Customers)
.Map(mc =>
{
mc.ToTable("RolesJoinCustomers");
mc.MapLeftKey("RoleId");
mc.MapRightKey("CustomerId");
});
}
}
}
تنظیمات روابط many-to-one
در تکمیل مدلهای مثال جاری، به دو کلاس زیر خواهیم رسید. در اینجا تنها در کلاس مشتری است که ارجاعی به کلاس آدرس او وجود دارد. در کلاس آدرس، یک navigation property همانند حالت 1:1 تعریف نشده است:
namespace EF_Sample35.Models
{
public class Address
{
public int Id { set; get; }
public string City { set; get; }
public string StreetAddress { set; get; }
public string PostalCode { set; get; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// …
public virtual Address Address { get; set; }
}
}
این رابطه توسط EF Code first به صورت خودکار به یک رابطه many-to-one تفسیر خواهد شد و نیازی به تنظیمات خاصی ندارد.
زمانیکه جداول برنامه تشکیل شوند، جدول Addresses موجودیتی مستقل خواهد داشت و جدول مشتری با یک فیلد به نام Address_Id به جدول آدرسها متصل میگردد. این فیلد نال پذیر است؛ به عبارتی ذکر آدرس مشتری الزامی نیست.
اگر نیاز بود این تعاریف نیز توسط Fluent API سفارشی شوند، باید خاصیت public virtual ICollection<Customer> Customers به کلاس Address نیز اضافه شود تا بتوان رابطه زیر را توسط کدهای برنامه تعریف کرد:
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// many-to-one
this.HasOptional(x => x.Address)
.WithMany(x => x.Customers)
.WillCascadeOnDelete();
}
}
}
متد HasOptional سبب میشود تا فیلد Address_Id اضافه شده به جدول مشتریها، null پذیر شود.