با این خصوصیات CSS شگفت زده شوید
شبیه به سشن، چند مورد دیگر را نیز میتوان به همین روش تامین کرد:
ioc.For<IIdentity>().Use(() => HttpContext.Current.User.Identity); ioc.For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current)); ioc.For<HttpServerUtilityBase>().Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server)); ioc.For<HttpRequestBase>().Use(ctx => ctx.GetInstance<HttpContextBase>().Request);
همانگونه که میدانید مقدار Identity پس از درج به آن تخصیص مییابد چنانچه بخواهید به این مقدار دسترسی پیدا کنید چندین روش به ازای اینکار وجود دارد که ما در این مقاله سه روش معمول را بررسی خواهیم نمود.
1- استفاده از متغییر سیستمی Identity@@
2- استفاده از تابع () Scope_Identity
3- استفاده از تابع Ident_Current
هر سه این توابع مقدار Identity ایجاد شده برای جداول را نمایش میدهند. اما تفاوت هایی باهم دارند که در ادامه مقاله این تفاوتها بررسی شده است.
1- متغییر سیستمی Identity@@ : این متغییر سیستمی حاوی آخرین Identity ایجاد شده به ازای Session جاری شما است. لازم به ذکر است اگر به واسته Insert شما، Identity دیگری در یک حوزه دیگر (مانند یک Trigger) ایجاد شود مقدار موجود در این متغییر حاوی آخرین Identity ایجاد شده است. (یعنی Identity ایجاد شده توسط آن تریگر و نه خود جدول). لازم به ذکر است این موضوع به طور کامل در ادامه مقاله شرح داده شده است.
2- استفاده از تابع()Scope_Identity : با استفاده از این تابع میتوانیم آخرین Identify ایجا دشده به ازای Session جاری را بدست آوریم. لازم به ذکر است مقادیر Identity ایجاد شده توسط سایر حوزهها تاثیر در مقدار بازگشتی توسط این تابع ندارد. در ادامه مقاله این موضوع به طور کامل بررسی شده است.
3- استفاده از تابع ident_Current : این تابع آخرین مقدار Identity موجود در یک جدول را نمایش میدهد. ذکر این نکته ضروری است که Identity ایجاد شده توسط سایر Sessionها هم روی خروجی این تابع تاثیرگذار است. چون این تابع آخرین Identity موجود در جدول را به شما نمایش میدهد و نه Identity ایجاد شده به ازای یکSession را.
برای بدست آوردن یک Identity کافی است که پس از درج رکورد در جدول مورد نظر متغییر سیستمی @@Identity و یا توابع Scope_Identity و یا Ident_Current را همانند مثال زیر Select کنید.
USE TEMPDB GO IF OBJECT_ID(N'Employees', N'U') IS NOT NULL DROP TABLE Employees1; GO CREATE TABLE Employees ( ID int IDENTITY, FirstName NVARCHAR(50), LastName NVARCHAR(50) ) GO INSERT INTO Employees (FirstName,LastName) VALUES (N'مسعود',N'طاهری') GO SELECT @@IDENTITY AS [@@IDENTITY] SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY()] SELECT IDENT_CURRENT('Employees1') AS [IDENT_CURRENT('Employees1')] GO
خروجی دستورات بالا پس از درج رکورد مورد نظر به صورت زیر است.
اما ممکن است از خودتان این سوال را بپرسید که آیا این توابع در سطح شبکه آخرین مقدار Identity درج شده توسط سایر Sessionها را نمایش میدهند و یا Session جاری را؟ (منظور Sessionی که درخواست مقدار موجود در identity را نموده است).
برای دریافت پاسخ این سوال مطابق مراحل اسکریپهای زیر را اجرا نمایید.
1-ایجاد جدول Employees1
USE TEMPDB GO IF OBJECT_ID(N'Employees1', N'U') IS NOT NULL DROP TABLE Employees1; GO CREATE TABLE Employees1 ( ID int IDENTITY(1,1), FirstName NVARCHAR(50), LastName NVARCHAR(50) ) GO
GO INSERT INTO Employees1(FirstName,LastName) VALUES (N'فرید',N'طاهری') GO SELECT @@IDENTITY AS [@@IDENTITY] SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY()] SELECT IDENT_CURRENT('Employees1') AS [IDENT_CURRENT('Employees1')] GO
همانگونه که ملاحضه میکنید @@Identity، Scope_Identity() و Ident_Current هر سه مقدار Identity (عدد 1) ایجاد شده بوسیله دستور Insert را به شما نمایش میدهند.
1- و در انتها در یک Session دیگر دستورات زیر را اجرا نمایید.(واکشی مقدار Identity)
USE tempdb GO SELECT @@IDENTITY AS [@@IDENTITY] SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY()] SELECT IDENT_CURRENT('Employees1') AS [IDENT_CURRENT('Employees1')] GO
همانطور که مشاهده میکنید در این Seesion ما از SQL خواستهایم آخرین مقدار Identity را به ما نشان داده شود. باید به این نکته توجه کنید با توجه به اینکه در این Session عملیات درجی هنوز انجام نگرفته است که ما Identity ایجاد شده را مشاهده نماییم. بنابراین صرفاً تابع Iden_Current مقدار Identity موجود در جدول را به ما نمایش میدهد.
پس میتوان به این نکته رسید که
@@Idnetity و Scope_Identity : Identity ایجاد به ازای Session جاری را نمایش داده و به مقادیر تولید شده توسط سایر Sessionهای دیگر دسترسی ندارد.
Ident_Current : آخرین Identity موجود در جدول را به شما نمایش میدهد. بنابراین باید این نکته را در نظر داشته باشید که Identityها ایجاد شده توسط سایر Sessionها روی مقدار بازگشتی این تابع تاثیرگدار است.
اما یکی دیگر از مباحث مهم درباره Identity تاثیر Scope بر مقدار Identity است (یعنی چه!) . برای اینکه با مفهوم این موضوع آشنا شوید اسکریپتهای مربوط به مثال زیر را بدقت اجرا کنید.
1- ایجاد جدول Employees1
USE TEMPDB GO IF OBJECT_ID(N'Employees1', N'U') IS NOT NULL DROP TABLE Employees1; GO CREATE TABLE Employees1 ( ID int IDENTITY(1,1), FirstName NVARCHAR(50), LastName NVARCHAR(50) ) GO
همانطور که مشاهده میکنید مقدار شروع برای Identity برابر 1 و گام افزایش هم برابر 1 در نظر گرفته شده است(Identity(1,1)) .
2- ایجاد جدول Employees2
USE TEMPDB GO IF OBJECT_ID(N'Employees2', N'U') IS NOT NULL DROP TABLE Employees2; GO CREATE TABLE Employees2 ( ID int IDENTITY(100,1), FirstName NVARCHAR(50), LastName NVARCHAR(50) ) GO
همانطور که مشاهده میکنید مقدار شروع برای Identity برابر 100 و گام افزایش هم برابر 1 در نظر گرفته شده است(Identity(100,1)).
3- ایجاد یک Trigger به ازای جدول Employees1
USE tempdb GO CREATE TRIGGER Employees1_Insert ON Employees1 FOR INSERT AS BEGIN INSERT Employees2(FirstName,LastName) SELECT FirstName,LastName FROM INSERTED END; GO
Trigger ایجاد شده به ازای جدول Employees1 به ازای عملیات Insert اجرا میشود. همچنین مقادیر درج شده در جدول Employees1 بوسیله جدول Inserted در دسترس است. لازم به ذکر است جدول Inserted یک جدول موقت بوده که توسط Trigger ایجاد شده و داخل خود آن معتبر است.
هدف ما از ایجاد این Trigger تهیه یک کپی از رکوردهایی که در جدول Employees1 درج میشوند است. این کپی قرار است با استفاده از دستور Insert…Select در جدول Employees2 ایجاد گردد.
4- درج یک رکورد در جدول Employees1 و واکشی مقدار Identity
USE tempdb GO INSERT INTO Employees1(FirstName,LastName) VALUES (N'مسعود',N'طاهری') GO SELECT @@IDENTITY AS [@@IDENTITY] SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY()] SELECT IDENT_CURRENT('Employees1') AS [IDENT_CURRENT('Employees1')] SELECT IDENT_CURRENT('Employees2') AS [IDENT_CURRENT('Employees2')] GO
مقادیر استخراج شده به ازای Identity به شرح زیر است
1- @@Identity : پس از درج رکورد در جدول Employees1 متغییر سیستمی @@Identity مقدار 100 را نمایش داده است دلیل این موضوع بر میگردد به Trigger موجود در جدول Employees1.
با توجه به اینکه جدول Employees1 دارای یک فیلد Identity بوده است هنگام درج رکورد در جدول مقدار @@Identity=1 است اما چون این جدول دارای Triggerی است که این Trigger خود با جدولی دیگری درگیر است که دارای Identity است مقدار متغییر @@identity=100 خواهد شد.
2- Scope_Identity() : مقدار نمایش داده شده توسط تابع Scope_Identity() برابر با مقدار Identity تخصیص (عدد 1) داده شده به ازای رکورد شما میباشد که این موضوع در اغلب موارد مد نظر برنامهنویسان میباشد.
3- Ident_Current(‘Employees1’) : مقدار نمایش شده توسط تابع Ident_Current آخرین مقدار Identity (عدد 1) موجود در جدول Employees1 است.
4- Ident_Current(‘Employees2’) : مقدار نمایش شده توسط تابع Ident_Current آخرین مقدار Identity (عدد 100) موجود در جدول Employees2 است.
چند نکته مهم
1- مقدار بازگردانده شده توسط تابع Ident_Current آخرین مقدار Identity موجود در جدول مورد نظر شما بوده است و عملیات درج سایر کاربران در این مقدار تاثیر گذار است.
2- برای بدست آوردن مقدار Identity درست بهتر است از تابع Scope_Identity() استفاده نماییم. معمولاً در بیشتر مواقع مقدار بازگردانده شده توسط این تابع مد نظر برنامه نویسان است.
3- EntityFramework و Nhibernate هم برای بدست آوردن Identity از تابع Scope_Identity استفاده میکند.
برای استفاده از این مزایا باید سرویس Microsoft SharePoint Foundation User Code Service فعال باشد .
استفاده از Sandbox Solution نیازمند 3 چیز است :
1 - User Code Service یا SPUCHostService.exe : این سرویس وظیفه مدیریت کدهای Sandbox روی سرور و میزبانی درخواستهای Sandbox به سرور را دارد.
2 - Sandbox Worker Process یا SPUCWorkerProcess.exe : این سرویس برای مدیریت پردازش کدهای اجرایی Sandbox استفاده میشود خصوصا در مورارد امنیتی (فرض کنید درون کد حلقه بی نهایتی وجود داشته باشد. اگر بار اجرایی آن بر روی w3wp.exe باشد ، باعث متوقف شدن کارکرد تمام پروسه میشود. بار این مسئولیت بر دوش SPUCWorkerProcess.exe میباشد )
3 - Sandbox Worker Process Proxy یا SPUCWorkerProcessProxy.exe : این سرویس برای اجرای کدهای Client Object Model در sandbox استفاده میشود.
می توانید ارتباط پردازههای فوق را در نمودار زیر مشاهد کنید :
با توجه به این توضیحات به دلیل استفاده از Sandbox میپردازیم :
1 - sandbox Solutionها امن هستند.
2 - sandbox Solutionها میتوانند مانیتور شوند.
3 - sandbox Solutionها حداقل تاثیر را روی هم دارند.
4 - sandbox Solutionها عملیات I/O کمی روی فایلهای سیستمی دارند
5 - sandbox Solutionها امکان debugging دارند
6 - sandbox Solutionها امکان توسعه ، انتشار و به روز رسانی دارند
7 - sandbox Solutionها امکان تعریف Policy برای CAS ایجاد میکند (Code Access Security برای قابل اطمینان ساخت کد ها)
8 - sandbox Solutionها امکان اعتبار سنجی به کمک کلاس SPSolutionValidator را میدهد.
9 - sandbox Solutionها امکان تعریف SLA های مختلف را میدهد.
چه قسمت هایی توسط Sandbox Solution پشتیبانی میشود :
هنگام ایجاد یک پروژه از نوع sandbox در ویژوال استودیو ، یکسری امکانات از برنامه نویس سلب میشود و محدودیتهای برای استفاده از کلاسها برای وی اعمال میشود .موارد زیر ، از جمله مواردی هستند که توسعه دهنده میتواند از آنها در sandbox استفاده کند :
Add-SPSolution c:\code\SharePointProject2\bin\debug\SharePointProject2.wsp
stsadm –o addsolution –name SharePointProject2.wsp
// See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!");
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
ب) فعال بودن ImplicitUsings که مختص به C# 10.0 است.
بررسی مفهوم global using directives در C# 10.0
هدف اصلی از وجود Using directives در زبان #C که از نگارش 1 آن در دسترس هستند، خلاصه نویسی نام طولانی اشیاء و متدها است. برای مثال نام اصلی متد Console.WriteLine به صورت System.Console.WriteLine است که با درج فضای نام System در ابتدای فایل، میتوان از ذکر مجدد آن جلوگیری کرد. از این دست میتوان به نوع System.Collections.Generic.List نیز اشاره کرد که کمتر کسی علاقمند است تا این نام طولانی را تایپ کند. به همین جهت با استفاده از یک using directive متناظر با فضای نام System.Collections.Generic، ذکر نام این نوع، به List خلاصه میشود.
طراحی دات نت 6 مبتنی بر سبک minimalism است! برای نمونه خلاصه کردن نزدیک به 10 سطر فایل Program.cs کلاسیک، به تنها یک سطر که به همراه ذکر using System در ابتدای آن هم نیست. در C# 10.0 دیگر نیازی نیست تا برای مثال ذکر using System را در دهها و یا صدها فایل، بارها و بارها تکرار کرد. برای اینکار تنها کافی است یکبار آنرا به صورت global تعریف کنیم و پس از آن دیگر نیازی به ذکر آن در کل پروژه نیست:
global using System;
چند نکته:
- امکان ترکیب global usingها و usingها معمولی در یک فایل هست.
- امکان تعریف global usingهای استاتیک نیز پیشبینی شدهاست:
global using static System.Console;
مفهوم جدید implicit global using directives در C# 10.0 و به کمک NET SDK 6.0.
تا اینجا دریافتیم که میتوان دایرکتیوهای سراسری using را در برنامه به صورت دستی تعریف و استفاده کرد. اما ... پروژهی کنسولی که به صورت پیشفرض توسط NET SDK 6.0. ایجاد میشود، به همراه هیچ global using ای نیست. این مورد توسط تنظیم زیر که جزئی از NET SDK 6.0. است، فعال میشود:
<ImplicitUsings>enable</ImplicitUsings>
// <auto-generated/> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks;
البته این فایل ویژه به ازای نوعهای پروژههای مختلف، محتوای متفاوتی را دارد. برای مثال در برنامههای ASP.NET Core، چنین محتوای پیشفرضی را پیدا میکند:
// <autogenerated /> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; global using global::System.Net.Http.Json; global using global::Microsoft.AspNetCore.Builder; global using global::Microsoft.AspNetCore.Hosting; global using global::Microsoft.AspNetCore.Http; global using global::Microsoft.AspNetCore.Routing; global using global::Microsoft.Extensions.Configuration; global using global::Microsoft.Extensions.DependencyInjection; global using global::Microsoft.Extensions.Hosting; global using global::Microsoft.Extensions.Logging;
روش حذف و یا اضافهی global usingهای پیشفرض
اگر به هر دلیلی نمیخواهید تعدادی از global usingهای پیشفرض به همراه گزینهی ImplicitUsings استفاده کنید، میتوانید آنها را در فایل csproj به صورت زیر، Remove و یا حتی موارد جدیدی را Include کنید:
<ItemGroup> <Import Remove="System.Threading" /> <Import Include="Microsoft.Extensions.Logging" /> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'"> </ItemGroup>
- مطالعه مسیر آموزشی "Entity Framework Code-First"
- مطالعه مسیر آموزشی "Asp.NET MVC"
- مطالعه مقالات مربوط به "Asp.net Identity"
- مطالعه مسیر آموزشی "اصول طراحی شی گرا SOLID" و دوره "بررسی مفاهیم معکوس سازی وابستگیها و ابزارهای مرتبط با آن"
- انجمن
- ارتباط دوستی
- سیستم ترفیع رتبه
- Themeable
- سیستم Following
- صفحات داینامیک
- سیستم پیام رسانی
- امکان ساخت گروههای شخصی برای انتشار مطالب خود (توسط کاربران) با اعمال دسترسی مختلف
- پیغام خصوصی
- وبلاگ
- نظرسنجی ها
- مدیریت کاربران با دسترسیها داینامیک
- اخبار
- آگهی ها
/// <summary> /// Represents the lable /// </summary> public class Tag { #region Ctor /// <summary> /// Create one instance of <see cref="Tag"/> /// </summary> public Tag() { Id = SequentialGuidGenerator.NewSequentialGuid(); } #endregion #region Properties /// <summary> /// sets or gets Tag's identifier /// </summary> public virtual Guid Id { get; set; } /// <summary> /// sets or gets Tag's name /// </summary> public virtual string Name { get; set; } #endregion #region NavigationProperties /// <summary> /// sets or gets Tag's posts /// </summary> public virtual ICollection<BlogPost> BlogPosts { get; set; } #endregion }
/// <summary> /// Represents the Post's Draft /// </summary> public class BlogDraft { #region Ctor /// <summary> /// create one instance of <see cref="BlogDraft"/> /// </summary> public BlogDraft() { Id = SequentialGuidGenerator.NewSequentialGuid(); } #endregion #region Properties /// <summary> /// gets or sets Id of post's draft /// </summary> public virtual Guid Id { get; set; } /// <summary> /// gets or sets body of post's draft /// </summary> public virtual string Body { get; set; } /// <summary> /// gets or set title of post's draft /// </summary> public virtual string Title { get; set; } /// <summary> /// gets or sets tags of post's draft that seperated using ',' /// </summary> public virtual string TagNames { get; set; } /// <summary> /// gets or sets value indicating whether this draft is ready to publish /// </summary> public virtual bool IsReadyForPublish { get; set; } /// <summary> /// ges ro sets DateTime that this draft added /// </summary> public virtual DateTime CreatedOn { get; set; } /// <summary> /// gets or sets information of User-Agent /// </summary> public virtual string Agent { get; set; } /// <summary> /// gets or sets date that this draft publish as ready /// </summary> public virtual DateTime? ReadyForPublishOn { get; set; } #endregion #region NavigationProperties /// <summary> /// gets or sets Id of user that he is owner of this draft /// </summary> public virtual long OwnerId { get; set; } /// <summary> /// gets or sets user that he is owner of this draft /// </summary> public virtual User Owner { get; set; } #endregion }
/// <summary> /// Section of Rating /// </summary> public enum RatingSection { News, Announcement, ForumTopic, BlogComment, NewsComment, PollComment, AnnouncementComment, ForumPost, ... } /// <summary> /// Represents Rating Record regard by section type for Rating System /// </summary> public class UserRating { #region Ctor /// <summary> /// Create one instance of <see cref="UserRating"/> /// </summary> public UserRating() { Id = SequentialGuidGenerator.NewSequentialGuid(); } #endregion #region Properties /// <summary> /// gets or sets Id of Rating Record /// </summary> public virtual Guid Id { get; set; } /// <summary> /// gets or sets value of rate /// </summary> public virtual double RatingValue { get; set; } /// <summary> /// gets or sets Section's Id /// </summary> public virtual long SectionId { get; set; } /// <summary> /// gets or sets Section /// </summary> public virtual RatingSection Section { get; set; } #endregion #region Navigation Properties /// <summary> /// gets or sets user that rate one section /// </summary> public virtual User Rater { get; set; } /// <summary> /// gets or sets Rater Id that rate one section /// </summary> public virtual long RaterId { get; set; } #endregion }
/// <summary> /// Represent the rating as ComplexType /// </summary> [ComplexType] public class Rating { /// <summary> /// sets or gets total of rating /// </summary> public virtual double? TotalRating { get; set; } /// <summary> /// sets or gets rater's count /// </summary> public virtual long? RatersCount { get; set; } /// <summary> /// sets or gets average of rating /// </summary> public virtual double? AverageRating { get; set; } }
/// <summary> /// Represents a base class for every content in system /// </summary> public abstract class BaseContent { #region Properties /// <summary> /// get or set identifier of record /// </summary> public virtual long Id { get; set; } /// <summary> /// gets or sets date of publishing content /// </summary> public virtual DateTime PublishedOn { get; set; } /// <summary> /// gets or sets Last Update's Date /// </summary> public virtual DateTime ModifiedOn { get; set; } /// <summary> /// gets or sets the blog pot body /// </summary> public virtual string Body { get; set; } /// <summary> /// gets or sets the content title /// </summary> public virtual string Title { get; set; } /// <summary> /// gets or sets value indicating Custom Slug /// </summary> public virtual string SlugUrl { get; set; } /// <summary> /// gets or sets meta title for seo /// </summary> public virtual string MetaTitle { get; set; } /// <summary> /// gets or sets meta keywords for seo /// </summary> public virtual string MetaKeywords { get; set; } /// <summary> /// gets or sets meta description of the content /// </summary> public virtual string MetaDescription { get; set; } /// <summary> /// gets or sets /// </summary> public virtual string FocusKeyword { get; set; } /// <summary> /// gets or sets value indicating whether the content use CanonicalUrl /// </summary> public virtual bool UseCanonicalUrl { get; set; } /// <summary> /// gets or sets CanonicalUrl That the Post Point to it /// </summary> public virtual string CanonicalUrl { get; set; } /// <summary> /// gets or sets value indicating whether the content user no Follow for Seo /// </summary> public virtual bool UseNoFollow { get; set; } /// <summary> /// gets or sets value indicating whether the content user no Index for Seo /// </summary> public virtual bool UseNoIndex { get; set; } /// <summary> /// gets or sets value indicating whether the content in sitemap /// </summary> public virtual bool IsInSitemap { get; set; } /// <summary> /// gets or sets a value indicating whether the content comments are allowed /// </summary> public virtual bool AllowComments { get; set; } /// <summary> /// gets or sets a value indicating whether the content comments are allowed for anonymouses /// </summary> public virtual bool AllowCommentForAnonymous { get; set; } /// <summary> /// gets or sets viewed count by rss /// </summary> public virtual long ViewCountByRss { get; set; } /// <summary> /// gets or sets viewed count /// </summary> public virtual long ViewCount { get; set; } /// <summary> /// Gets or sets the total number of comments /// <remarks>The same as if we run Item.Comments.where(a=>a.Status==Status.Approved).Count() /// We use this property for performance optimization (no SQL command executed) /// </remarks> /// </summary> public virtual int ApprovedCommentsCount { get; set; } /// <summary> /// Gets or sets the total number of comments /// <remarks>The same as if we run Item.Comments.where(a=>a.Status==Status.UnApproved).Count() /// We use this property for performance optimization (no SQL command executed)</remarks></summary> public virtual int UnApprovedCommentsCount { get; set; } /// <summary> /// gets or sets value indicating whether the content is logical deleted or hidden /// </summary> public virtual bool IsDeleted { get; set; } /// <summary> /// gets or sets rating complex instance /// </summary> public virtual Rating Rating { get; set; } /// <summary> /// gets or sets value indicating whether the content show with rssFeed /// </summary> public virtual bool ShowWithRss { get; set; } /// <summary> /// gets or sets value indicating maximum days count that users can send comment /// </summary> public virtual int DaysCountForSupportComment { get; set; } /// <summary> /// gets or sets information of User-Agent /// </summary> public virtual string Agent { get; set; } /// <summary> /// gets or sets icon name with size 200*200 px for snippet /// </summary> public virtual string SocialSnippetIconName { get; set; } /// <summary> /// gets or sets title for snippet /// </summary> public virtual string SocialSnippetTitle { get; set; } /// <summary> /// gets or sets description for snippet /// </summary> public virtual string SocialSnippetDescription { get; set; } /// <summary> /// gets or sets body of content's comment /// </summary> public virtual byte[] RowVersion { get; set; } /// <summary> /// gets or sets name of tags seperated by comma that assosiated with this content fo increase performance /// </summary> public virtual string TagNames { get; set; } /// <summary> /// gets or sets counter for Content's report /// </summary> public virtual int ReportsCount { get; set; } #endregion #region NavigationProperties /// <summary> /// get or set user that create this record /// </summary> public virtual User Author { get; set; } /// <summary> /// gets or sets Id of user that create this record /// </summary> public virtual long AuthorId { get; set; } /// <summary> /// get or set the tags integrated with content /// </summary> public virtual ICollection<Tag> Tags { get; set; } #endregion }
بخشهای مختلفی که در ابتدای مقاله مطرح شدند، دارای یکسری خصوصیات مشترک میباشند و برای این منظور این خصوصیات را در یک کلاس پایه کپسوله کردهایم. شاید تفکر شما این باشد که میخواهیم ارث بری TPH یا TPT را اعمال کنیم. ولی با توجه به سلیقهی شخصی، در این بخش قصد استفاده از ارث بری را ندارم.
نکتهای که وجود دارد فیلدهای ApprovedCommentsCount UnApprovedCommentsCount و TagNames میباشند که هنگام درج نظر جدید باید تعداد نظرات ذخیره شده را ویرایش کنیم و هنگام ویرایش خود پست یا خبر با ... و یا حتی ویرایش خود تگ یا حذف آن تگ باید TagNames که لیست برچسبهای محتوا را به صورت جدا شده با (,) از هم دیگر میباشد، ویرایش کنیم (جای بحث دارد).
مشخص است که هر یک از مطالب منتشر شده در بخشهای وبلاگ، اخبار، نظرسنجی و آگهیها، یک کابر ایجاد کننده (Author نامیدهایم) خواهد داشت و هر کاربر هم میتواند چندین مطلب را ایجاد کند. لذا رابطهی یک به چند بین تمام این بخشها مذکور و کاربر ایجاد خواهد شد.
مدل LinkBack
/// <summary> /// Represents link for implemention linkback /// </summary> public class LinkBack { #region Ctor /// <summary> /// create one instance of <see cref="LinkBack"/> /// </summary> public LinkBack() { CreatedOn = DateTime.Now; Id = SequentialGuidGenerator.NewSequentialGuid(); } #endregion #region Properties /// <summary> /// gets or sets link's Id /// </summary> public virtual Guid Id { get; set; } /// <summary> /// gets or sets text for show Link /// </summary> public virtual string Title { get; set; } /// <summary> /// gets or sets link's address /// </summary> public virtual string Url { get; set; } /// <summary> /// gets or set value indicating whether this link is internal o external /// </summary> public virtual LinkBackType Type { get; set; } /// <summary> /// gets or sets date that this record is added /// </summary> public virtual DateTime CreatedOn { get; set; } #endregion #region NavigationProperties /// <summary> /// gets or sets Post that associated /// </summary> public virtual BlogPost Post { get; set; } /// <summary> /// gets or sets id of Post that associated /// </summary> public virtual long PostId { get; set; } #endregion } /// <summary> /// represents Type of ReferrerLinks /// </summary> public enum LinkBackType { /// <summary> /// Internal link /// </summary> Internal, /// <summary> /// External Link /// </summary> External }
مطمئنا در خیلی از وبلاگها مثل سایت جاری متوجه نمایش لینکها ارجاع دهندههای خارجی و داخلی در زیر مطلب شدهاید. کلاس LinkBack هم دقیقا برای این منظور در نظرگرفته شده است که عنوان صفحهای که این پست در آنجا لینک داده شده است، به همراه آدرس آن صفحه، در جدول حاصل از این کلاس ذخیره خواهند شد. نوع داده LinkBackType هم برای متمایز کردن رکوردهای درج شده به عنوان LinkBack در نظر گرفته شده است که بتوان آنها را متمایز کرد، به ارجاعات داخلی و خارجی.
مدل پست ها
/// <summary> /// Represents a blog post /// </summary> public class BlogPost : BaseContent { #region Ctor /// <summary> /// Create one Instance of <see cref="BlogPost"/> /// </summary> public BlogPost() { Rating = new Rating(); PublishedOn = DateTime.Now; } #endregion #region Properties /// <summary> /// gets or sets Status of LinkBack Notifications /// </summary> public virtual LinkBackStatus LinkBackStatus { get; set; } #endregion #region NavigationProperties /// <summary> /// get or set blog post's Reviews /// </summary> public virtual ICollection<BlogComment> Comments { get; set; } /// <summary> /// get or set collection of links that reference to this blog post /// </summary> public virtual ICollection<LinkBack> LinkBacks { get; set; } /// <summary> /// get or set Collection of Users that Contribute on this post /// </summary> public virtual ICollection<User> Contributors { get; set; } #endregion } /// <summary> /// Represents Status for ReferrerLinks /// </summary> public enum LinkBackStatus { [Display(Name ="غیرفعال")] Disable, [Display(Name = "فعال")] Enable, [Display(Name = "لینکها داخلی")] JustInternal, [Display(Name = "لینکها خارجی")] JustExternal }
/// <summary> /// Represents a base class for every comment in system /// </summary> public abstract class BaseComment { #region Properties /// <summary> /// get or set identifier of record /// </summary> public virtual long Id { get; set; } /// <summary> /// gets or sets date of creation /// </summary> public virtual DateTime CreatedOn { get; set; } /// <summary> /// gets or sets displayName of this comment's Creator if he/she is Anonymous /// </summary> public virtual string CreatorDisplayName { get; set; } /// <summary> /// gets or sets body of blog post's comment /// </summary> public virtual string Body { get; set; } /// <summary> /// gets or sets body of blog post's comment /// </summary> public virtual Rating Rating { get; set; } /// <summary> /// gets or sets informations of agent /// </summary> public virtual string UserAgent { get; set; } /// <summary> /// gets or sets siteUrl of Creator if he/she is Anonymous /// </summary> public virtual string SiteUrl { get; set; } /// <summary> /// gets or sets Email of Creator if he/she is anonymous /// </summary> public virtual string Email { get; set; } /// <summary> /// gets or sets status of comment /// </summary> public virtual CommentStatus Status { get; set; } /// <summary> /// gets or sets Ip Address of Creator /// </summary> public virtual string CreatorIp { get; set; } /// <summary> /// gets or sets datetime that is modified /// </summary> public virtual DateTime? ModifiedOn { get; set; } /// <summary> /// gets or sets counter for report this comment /// </summary> public virtual int ReportsCount { get; set; } #endregion #region NavigationProperties /// <summary> /// get or set user that create this record /// </summary> public virtual User Creator { get; set; } /// <summary> /// get or set Id of user that create this record /// </summary> public virtual long? CreatorId { get; set; } #endregion } public enum CommentStatus { /* 0 - approved, 1 - pending, 2 - spam, -1 - trash */ [Display(Name = "تأیید شده")] Approved = 0, [Display(Name = "در انتظار بررسی")] Pending = 1, [Display(Name = "جفنگ")] Spam = 2, [Display(Name = "زباله دان")] Trash = -1 }
/// <summary> /// Represents a blog post's comment /// </summary> public class BlogComment : BaseComment { #region Ctor /// <summary> /// Create One Instance for <see cref="BlogComment"/> /// </summary> public BlogComment() { Rating = new Rating(); CreatedOn = DateTime.Now; } #endregion #region NavigationProperties /// <summary> /// gets or sets BlogComment's identifier for Replying and impelemention self referencing /// </summary> public virtual long? ReplyId { get; set; } /// <summary> /// gets or sets blog's comment for Replying and impelemention self referencing /// </summary> public virtual BlogComment Reply { get; set; } /// <summary> /// get or set collection of blog's comment for Replying and impelemention self referencing /// </summary> public virtual ICollection<BlogComment> Children { get; set; } /// <summary> /// gets or sets post that this comment sent to it /// </summary> public virtual BlogPost Post { get; set; } /// <summary> /// gets or sets post'Id that this comment sent to it /// </summary> public virtual long PostId { get; set; } #endregion }