در این قسمت به پیاده سازی و توضیح مدلهای انجمن خواهیم پرداخت. قبل از شروع پیشنهاد میکنم مقالات قبلی را مطالعه کنید.
همکاران این قسمت:
سلمان معروفی
سید مجتبی حسینی
پیشنیاز این قسمت:
مقالات SQL Antipattern
سعی کردیم چندین پروژهی سورس باز را هم بررسی کنیم و در نهایت کاملترین و بهترین روش را پیاده سازی کنیم. NForum ، MyBB ، MVCForum ، بخش CMS مربوط به SmartStore و ساختار دیتابیس StackOverFlow ازجملهی آنها هستند.
/// <summary> /// Represents the Forum /// </summary> public class Forum { #region Properties /// <summary> /// gets or sets Id that Identify Forum /// </summary> public virtual long Id { get; set; } /// <summary> /// gets or sets Forum's title /// </summary> public virtual string Title { get; set; } /// <summary> /// gets or sets Description of forum /// </summary> public virtual string Description { get; set; } /// <summary> /// gets or sets value indicating Custom Slug /// </summary> public virtual string SlugUrl { get; set; } /// <summary> /// gets or sets order for display forum /// </summary> public virtual long DisplayOrder { get; set; } /// <summary> /// Indicating This Forum is Active or Not /// </summary> public virtual bool IsActive { get; set; } /// <summary> /// Indicating This Forum is Close or Not /// </summary> public virtual bool IsClose { get; set; } /// <summary> /// Indicating This Forum is Private or Not /// </summary> public virtual bool IsPrivate { get; set; } /// <summary> /// sets or gets password for login to Private forums /// </summary> public virtual string PasswordHash { get; set; } /// <summary> /// sets or gets depth of forum in tree structure of forums /// </summary> public virtual int Depth { get; set; } /// <summary> /// sets or gets Count of posts That they are Approved /// </summary> public virtual long ApprovedPostsCount { get; set; } /// <summary> /// sets or gets Count of topics That they are Approved /// </summary> public virtual long ApprovedTopicsCount { get; set; } /// <summary> /// Gets or sets the id of last topic /// </summary> public virtual long LastTopicId { get; set; } /// <summary> /// gets or sets date of creation of last topic /// </summary> public virtual DateTime? LastTopicCreatedOn { get; set; } /// <summary> /// gets or sets title of last topic /// </summary> public virtual string LastTopicTitle { get; set; } /// <summary> /// gets or sets creator of last topic /// </summary> public virtual string LastTopicCreator { get; set; } /// <summary> /// gets or sets id of creator that create last topic /// </summary> public virtual long LastTopicCreatorId { get; set; } /// <summary> /// Indicate in this Forum Moderate Topics Before Display /// </summary> public virtual bool ModerateTopics { get; set; } /// <summary> /// Indicate in this Forum Moderate Posts Before Dipslay /// </summary> public virtual bool ModeratePosts { get; set; } /// <summary> /// gets or sets Count of posts that they are UnApproved /// </summary> public virtual long UnApprovedPostsCount { get; set; } /// <summary> /// gets or sets Count of topics that they are UnApproved /// </summary> public virtual long UnApprovedTopicsCount { get; set; } /// <summary> /// gets or sets Rowversion /// </summary> public virtual byte[] RowVersion { 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 path for tree structure antipattern (1/3/4/23) /// </summary> public virtual string Path { get; set; } /// <summary> /// Indicate this forum inherit moderators from parent forum /// </summary> public virtual bool IsModeratorsInherited { get; set; } /// <summary> /// gets or set datetime that Last Post is Created In this forum. used for ForumTracking /// </summary> public virtual DateTime? LastPostCreatedOn { get; set; } #endregion #region NavigationProperties /// <summary> /// sets or gets identifier forum's parent /// </summary> public virtual long? ParentId { get; set; } /// <summary> /// sets or gets forum's parent /// </summary> public virtual Forum Parent { get; set; } /// <summary> /// sets or gets sub forums of forum /// </summary> public virtual ICollection<Forum> Children { get; set; } /// <summary> /// set or get topics of forum /// </summary> public virtual ICollection<ForumTopic> Topics { get; set; } /// <summary> /// get or set moderators of this forum /// </summary> public virtual ICollection<ForumModerator> Moderators { get; set; } /// <summary> /// get or set Subscriptions List /// </summary> public virtual ICollection<User> Subscribers { get; set; } /// <summary> /// get or set Announcements Collection of this Forum /// </summary> public virtual ICollection<ForumAnnouncement> Announcements { get; set; } /// <summary> /// get or set Trackers List Of this Forum /// </summary> public virtual ICollection<ForumTracker> Trackers { get; set; } /// <summary> /// get or set Posts List that Posted in this forum for increase Performance for get Posts Count /// </summary> public virtual ICollection<ForumPost> Posts { get; set; } /// <summary> /// get or set /// </summary> public virtual ICollection<ForumTopicTracker> TopicTrackers { get; set; } #endregion
- IsActive : مشخص کنندهی این است که در این انجمن امکان ارسال تاپیک و پست وجود دارد و در صورت false بودن این خصوصیت، بر تمام زیر انجمنها هم اعمال خواهد شد و برای زمانی مفید است که میخواهیم برای مدتی به هر دلیل خاصی امکان ارسال تاپیک و پست را برای انجمن خاصی، ندهیم.
- IsColsed : خصوصت اولی که مطرح شد اگر مقدار false بگیرد، همچنان کاربران میتوانند تایپکها و پستهای قبلی را مشاهده و مطالعه کنند. ولی با مقدار دهی این خصوصیت با مقدار false، امکان کلیهی فعالیتها و مشاهدهای را از محتوای این انجمن و زیر انجمنهای آن نخواهیم داشت.
- IsPrivate : برای مواقعی که لازم است برای انجمن خاصی کلمهی عبور در نظر بگیریم تا افراد خاص که کلمهی عبور آن را دارند بتوانند در آن انجمن فعالیت کنند، در نظر گرفته شده است.
- ApprovedPostsCount , UnApprovedPostsCount,ApprovedTopicsCount,UnApprovedTopicsCount : برای بالا بردن کارآیی سیستم به مانند مدلهای قبل در نظر گرفته شدهاند.
- LastTopicId, LastTopicTitle , LastTopicCreator , LastTopicCreatorId , LastTopicCreatedOn: همچنین برای افزایش کارآیی سیستم و نمایش به عنوان قسمتی از مشخصات قابل مشاهده از هر انجمن، در نظر گرفته شدهاند.
- Depth : برای نشان دادن عمق گره در درخت استفاده میشود که هنگام درج انجمن، این مورد از نتیجهی جمع عمق پدر انتخاب شده و یک، به دست خواهد آمد. این مورد هنگام واکشی برای مثال 4 سطح اول برای نمایش آنها در صفحهی اول انجمن به صورت سلسله مراتبی خیلی مفید خواهد بود.
- Path : برای استفاده از SQL Antipattern شمارش مسیر در نظر گرفته شده است. این مورد جزء Best Practiceها میتواند باشد. چون هم با استفاده از ساختار خود ارجاع، درخت خود را داریم و با این Antipattern کوئریهای مربوط به درخت خیلی راحت خواهد بود.
- IsModeratorsInherited : اگر لازم است مدیران انجمن، پدر را به عنوان مدیر خود قبول کنند، این خصوصیت مقدار true خواهد گرفت.
- Subscribers : هر انجمنی میتواند یکسری مشترک نیز داشته باشد (به منظور اطلاع رسانی با درج یک تاپیک جدید در خود انجمن یا زیر انجمنهای آن) .
- Posts : به منظور افزایش کارایی هنگام محاسبه تعداد پستهای ارسالی در یک انجمن ، در نظر گرفته شده است.
- TopicTrackers : در مقاله بعد توضیح داده خواهد شد.
- LastPostCreatedOn : به منظور استفاده از آن برای سیستم Tracking انجمنها استفاده خواهد شد .
/// <summary> /// Represents The Moderator For Forum /// </summary> public class ForumModerator { #region NavigationProperties /// <summary> /// gets or sets Forum /// </summary> public virtual Forum Forum { get; set; } /// <summary> /// gets or sets identifier of forum /// </summary> public virtual long ForumId { get; set; } /// <summary> /// gets or sets user that moderate forum /// </summary> public virtual User Moderator { get; set; } /// <summary> /// gets or sets id of user that moderate forum /// </summary> public virtual long ModeratorId { get; set; } /// <summary> /// gets or sets permission of user that moderate forum /// </summary> public virtual ForumModeratorPermissions Permissions { get; set; } /// <summary> /// indicate moderator's permissions in this forum apply with /// </summary> public virtual bool ApplyChildren { get; set; } #endregion } [Flags] public enum ForumModeratorPermissions { CanEditPosts=1, CanDeletePosts=2, CanManageTopics=4, CanOpenCloseTopics=8, ... }
- ApplyChildren : برای اعمال دسترسیهای مدیریتی کاربر x به زیر انجمنهای انجمن y البته اگر خصوصیت IsModeratorsInherited زیر انجمنهای مورد نظر با مقدار true مقدار دهی شده باشد.
- Permissions : از نوع ForumModeratorPermissions و نگهدارنده دسترسیهای کاربر x به عنوان مدیر انجمن y، میباشد.
- نکته : برای این مدل آی دی در نظر گرفته نشده است و از کلید مرکب متشکل از ForumId و ModeratorId استفاده خواهیم کرد.
/// <summary> /// Represents the Announcement that shown Top Of Forums /// </summary> public class ForumAnnouncement { #region Ctor /// <summary> /// create one instance of <see cref="ForumAnnouncement"/> /// </summary> public ForumAnnouncement() { Id = SequentialGuidGenerator.NewSequentialGuid(); CreatedOn = DateTime.Now; } #endregion #region Properties /// <summary> /// gets or sets Identifier /// </summary> public virtual Guid Id { get; set; } /// <summary> /// gets or sets DateTime That this Announcement Will be Shown /// </summary> public virtual DateTime StartOn { get; set; } /// <summary> /// gets or sets DateTime That this Announcement Will be Finished /// </summary> public virtual DateTime? ExpireOn { get; set; } /// <summary> /// gets or sets Content of this Announcement /// </summary> public virtual string Message { get; set; } /// <summary> /// Indicate this Announcement Will be shown on Children Forums /// </summary> public virtual bool ApplyChildren { get; set; } /// <summary> /// gets or sets datetime that this record created /// </summary> public virtual DateTime CreatedOn { get; set; } #endregion #region NavigationProperties /// <summary> /// gets or sets Forum that associated With this Announcement /// </summary> public virtual Forum Forum { get; set; } /// <summary> /// gets or sets Identifier of Forum that associated With this Announcement /// </summary> public virtual long ForumId { get; set; } #endregion }
- ApplyChildren : برای مشخص کردین نمایش این اعلان در زیر انجمنهای انجمن مورد نظر
- ExpireOn : به این دلیل نال پذیر در نظر گرفته شده است که اگر لازم بود، در زمان مشخصی به پایان نرسد و با null مقدار دهی شود.
/// <summary> /// Represents a base class for AuditLog /// </summary> public abstract class AuditBaseEntity { #region Properties /// <summary> /// sets or gets identifier /// </summary> public virtual long Id { get; set; } /// <summary> /// gets or sets datetime that is created /// </summary> public virtual DateTime CreatedOn { get; set; } /// <summary> /// gets or sets datetime that is modified /// </summary> public virtual DateTime? LastModifiedOn { get; set; } /// <summary> /// gets or sets reason of Last Update for increase performance /// </summary> public virtual string LastModifyReason { get; set; } /// <summary> /// gets or sets displayName of Last Modifier for increase performance /// </summary> public virtual string LastModifier{ get; set; } /// <summary> /// indicate this entity is Locked for Modify /// </summary> public virtual bool ModifyLocked { get; set; } /// <summary> /// gets or sets rowversion for synchronization problem /// </summary> public virtual byte[] RowVersion { get; set; } /// <summary> /// gets or sets count of this content's Updates /// </summary> public virtual int ModifyCount { get; set; } #endregion #region NavigationProperties /// <summary> /// gets or sets creator of this record /// </summary> public virtual User Creator { get; set; } /// <summary> /// gets or sets creator's Id of this record /// </summary> public virtual long CreatorId { get; set; } #endregion }
/// <summary> /// Represents the Topic in the Forums /// </summary> public class ForumTopic { #region Ctor /// <summary> /// create one instance of <see cref="ForumTopic"/> /// </summary> public ForumTopic() { CreatedOn = DateTime.Now; } #endregion #region Properties /// <summary> /// sets or gets identifier /// </summary> public virtual long Id { get; set; } /// <summary> /// gets or sets datetime that is created /// </summary> public virtual DateTime CreatedOn { get; set; } /// <summary> /// gets or sets Title Of this topic /// </summary> public virtual string Title { get; set; } /// <summary> /// gets or sets name of tags that assosiated with /// this content fo increase performance /// </summary> public virtual string TagNames { get; set; } /// <summary> /// indicate this topic is Sticky and will be shown top of forum /// </summary> public virtual bool IsSticky { get; set; } /// <summary> /// indicate this topic is closed /// </summary> public virtual bool IsClosed { get; set; } /// <summary> /// gets or sets identifier of last post in this topic /// </summary> public virtual long LastPostId { get; set; } /// <summary> /// gets or sets identifier of Last user that post in this topic /// </summary> public virtual long LastPosterId { get; set; } /// <summary> /// gets or sets title of last Post in this topic /// </summary> public virtual string LastPostTitle { get; set; } /// <summary> /// gets or sets displayName of user that create lastpost in this topic /// </summary> public virtual string LastPoster { get; set; } /// <summary> /// gets or sets datetime that last post posted in this topic /// </summary> public virtual DateTime? LastPostCreatedOn { get; set; } /// <summary> /// indicate this topic is approved /// </summary> public virtual bool IsApproved { get; set; } /// <summary> /// indicate this topic is type of Announcements and shown in Annoucements sections /// </summary> public virtual bool IsAnnouncement { get; set; } /// <summary> /// gets or sets viewed count /// </summary> public virtual long ViewCount { get; set; } /// <summary> /// gets or sets count of posts that they are approved /// </summary> public virtual int ApprovedPostsCount { get; set; } /// <summary> /// gets or sets count of posts that they are Unapproved /// </summary> public virtual int UnApprovedPostsCount { get; set; } /// <summary> /// gets or sets specifications of this topic's rating /// </summary> public virtual Rating Rating { get; set; } /// <summary> /// gets or sets datetime that this topic closed /// </summary> public virtual DateTime? ClosedOn { get; set; } /// <summary> /// gets or sets reason that this topic colsed /// </summary> public virtual string ClosedReason { get; set; } /// <summary> /// gets or sets count of reports /// </summary> public virtual int ReportsCount { get; set; } /// <summary> /// indicate the posts of this topic should be Moderate Before Dipslay /// </summary> public virtual bool ModeratePosts { get; set; } /// <summary> /// gets or sets Level of this topic /// </summary> public virtual ForumTopicLevel Level { get; set; } /// <summary> /// gets or sets type of this topic /// </summary> public virtual ForumTopicType Type { get; set; } #endregion #region NavigationProperties /// <summary> /// gets or sets Collection of tags that associated with this topic /// </summary> public virtual ICollection<Tag> Tags { get; set; } /// <summary> /// gets or sets forum /// </summary> public virtual Forum Forum { get; set; } /// <summary> /// gets or sets identifier of Forum /// </summary> public virtual long ForumId { get; set; } /// <summary> /// gets or sets Posts Of this topic /// </summary> public virtual ICollection<ForumPost> Posts { get; set; } /// <summary> /// get or set Subscriptions List /// </summary> public virtual ICollection<User> Subscribers { get; set; } /// <summary> /// get or set Trackkers list of this Topic /// </summary> public virtual ICollection<ForumTopicTracker> Trackers { get; set; } /// <summary> /// gets or sets creator of this record /// </summary> public virtual User Creator { get; set; } /// <summary> /// gets or sets creator's Id of this record /// </summary> public virtual long CreatorId { get; set; } #endregion } public enum ForumTopicType { Non, Tutorial, Conversation, Question, News, Article } public enum ForumTopicLevel { Professional, Intermediate, Beginner }
- LastPostId , LastPosterId, LastPoster , LastPostTitle ,LastPostCreatedOn: برای افزایش کارآیی سیستم در نظر گرفته شدهاند.
- ModeratePosts : اگر لازم است پستهای یک تاپیک خاص، قبل از نمایش مدیریت شوند، با true مقدار دهی خواهد شد.
- Tags : لیستی از برچسبها که برای اعمال رابطهی چند به چند با مدل برچسبهای معرفی شدهی در مقاله اول، در نظر گرفته شده است.
- Posts : در هر تاپیکی یک سری پست به عنوان جوابهای آن ارسال خواهد شد.
- Subscribers : به مانند انجمنها، تاپیکهای ما هم میتوانند یک سری مشترک داشته باشند، تا از تغییرات این تاپیک مطلع شوند .
- Trackers : مربوط به سیستم Tracking تاپیک میباشد. و در مقاله بعد توضیح داده خواهد شد.
حتما لازم خواهد بود تاریخچهی تغییرات برای پستهای ارسالی ذخیره شوند؛ در مقالهی بعدی به این موضوع هم خواهیم پرداخت.