سؤال

النظر في المسائل التالية شرط لبناء منتدى التطبيق

مشاركة الوالدين

- Child Post1

    - Child Post1-1
    - Child Post1-2
        - Child Post1-2-1
- Child Post2
    - Child Post

- Child Post3

بنية الجدول

tblPost -

  • PostId
  • ChildPostId
  • العنوان
  • نشر المحتوى
  • اسم المستخدم

=====================

أنا يمكن أن لإستعادة هذا النوع من البيانات باستخدام العودية CTE.أنا متأكد من أن هذا هو أفضل نهج.

الأسئلة

  • ما هي أفضل طريقة لإستعادة هذه البيانات باستخدام SQL ؟

  • هل هناك طريقة أفضل لتحميل هذه البيانات باستخدام ORM?

  • إذا ذهبنا SQL الطريق ، ما هي أفضل طريقة لتحميل هذه البيانات إلى فئة كما هو مبين أدناه:

    public class Post {
      public int PostId {get;set;}
      public string PostTitle {get;set;}
      public string PostContent {get;set;}
      public string PostedBy {get;set;}
      public IEnumerable<Post> ChildPosts {get;set;}
    }
    
  • ماذا عن عرض هذا النوع من البيانات أقول باستخدام الشفرة جملة لعرض??

هل كانت مفيدة؟

المحلول

حسب تعليقك أنت منفتحون على اقتراحات حول تحسين الحالي الخاص بك مخطط قاعدة البيانات التي في الأساس post_id و child_post_id الأعمدة لأداء العلاقة الهرمية.

لذلك دعونا المضي قدما:

ما هي أفضل طريقة لإستعادة هذه البيانات باستخدام SQL ؟

أنصح لك أن نلقي نظرة على المقالة التالية الذي يوضح جميل جدا أسلوب إدارة هذه البيانات الهرمية في وسيلة فعالة جدا.فإنه يستخدم على مجموعة متداخلة نموذج حيث يمكنك تحديد مجموعات مع اليسار واليمين العقد ثم كنت قادرا على بناء الشجرة بأكملها مع واحد استعلام SQL:

enter image description here

هل هناك طريقة أفضل لتحميل هذه البيانات باستخدام ORM?

هناك طرق القيام بذلك باستخدام ORM مثل NHibernate و EF ولكن سوف أترك هذا في المرة القادمة.قد تفكر في تقسيم الأسئلة إلى العديد من الأسئلة مثل هذا الموضوع واسع جدا.إذا كنت تعلم كيفية القيام بذلك باستخدام عادي ADO.NET وسوف جمع أفضل بكثير فهم التقنيات الأساسية التي تشارك بحيث غدا كنت ترغب في استخدام هذه ORM سوف نعرف بالفعل ما تبحث عنه في أمر من كفاءة الاستعلامات.

ماذا عن عرض هذا النوع من البيانات أقول باستخدام الحلاقة جملة إطلالة??

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

حتى على افتراض النموذج التالي:

public class Post
{
    public int PostId { get; set; }
    public string PostTitle { get; set; }
    public IEnumerable<Post> ChildPosts { get; set; }
}

التالية تحكم (التي من الواضح لدي ضمنية القيم ولكن بعد قراءة البرنامج التعليمي لدي مرتبطة في بداية هذا المنصب سوف تكون قادرة على بناء هذا النموذج مع واحد استعلام SQL):

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Hardcoding the model here, but you could use the 
        // Nested Set Model technique I have linked to 
        // in order to build this model from your database
        var post = new Post
        {
            PostId = 1,
            PostTitle = "Parent Post",
            ChildPosts = new[]
            {
                new Post 
                {
                    PostId = 2,
                    PostTitle = "Child Post 1",
                    ChildPosts = new[]
                    {
                        new Post 
                        {
                            PostId = 3,
                            PostTitle = "Child Post 1-1",
                            ChildPosts = new[]
                            {
                                new Post
                                {
                                    PostId = 4,
                                    PostTitle = "Child Post 1-2-1"
                                }
                            }
                        },
                        new Post 
                        {
                            PostId = 5,
                            PostTitle = "Child Post 1-2"
                        },
                    }
                },

                new Post 
                {
                    PostId = 6,
                    PostTitle = "Child Post 2",
                    ChildPosts = new[]
                    {
                        new Post
                        {
                            PostId = 7,
                            PostTitle = "Child Post"
                        }
                    }
                },
                new Post 
                {
                    PostId = 8,
                    PostTitle = "Child Post 3"
                },
            }
        };
        return View(post);
    }
}

ثم سيكون لديك ~/Views/Home/Index.cshtml عرض:

@model Post
<ul>
    @Html.DisplayForModel()
</ul>

وطبعا المقابلة عرض القالب (~/Views/Home/DisplayTemplates/Post.cshtml) والتي سوف تكون متكررة في حالتنا لتقديم كامل الشجرة:

@model Post
<li>
    @Html.DisplayFor(x => x.PostTitle)
    <ul>
        @Html.DisplayFor(x => x.ChildPosts)
    </ul>
</li>

وبالطبع فإن النتيجة النهائية هي ما قد يتوقع المرء:

enter image description here


تحديث:

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

CREATE TABLE posts (id int primary key, left int, right int, title nvarchar(100));

و أن كنت قد ملأت مع الوظائف:

INSERT INTO posts (id, left, right, title) VALUES (1, 1, 16, 'Parent Post');
INSERT INTO posts (id, left, right, title) VALUES (2, 2, 9, 'Child Post1');
INSERT INTO posts (id, left, right, title) VALUES (3, 3, 4, 'Child Post1-1');
INSERT INTO posts (id, left, right, title) VALUES (4, 5, 8, 'Child Post1-2');
INSERT INTO posts (id, left, right, title) VALUES (5, 6, 7, 'Child Post1-2-1');
INSERT INTO posts (id, left, right, title) VALUES (6, 10, 13, 'Child Post2');
INSERT INTO posts (id, left, right, title) VALUES (7, 11, 12, 'Child Post');
INSERT INTO posts (id, left, right, title) VALUES (8, 14, 15, 'Child Post3');

الآن أنت يمكن أن تجلب لهم.

ولكن كما هو الحال دائما قبل فعلا القيام شيء يمكنك أن تصف ما تريد القيام به.وهذا هو:تعريف العقد:

public interface IPostsRepository
{
    Post GetPost();
}

الآن يمكنك الحصول على القيام.في هذه الحالة سوف نستخدم عادي ADO.NET الاستعلام عن قاعدة البيانات و بنيت وظيفة الكائن.سوف نستخدم خوارزمية تكرارية مع كومة لبناء شجرة ولكن هل يمكن أيضا استخدام خوارزمية العودية:

public class PostsRepositoryAdoNet: IPostsRepository
{
    private readonly string _connectionString;
    public PostsRepositoryAdoNet(string connectionString)
    {
        _connectionString = connectionString;
    }

    private class Scalar
    {
        public int Depth { get; set; }
        public Post Post { get; set; }
    }

    public Post GetPost()
    {
        using (var conn = new SqlConnection(_connectionString))
        using (var cmd = conn.CreateCommand())
        {
            conn.Open();
            cmd.CommandText =
            @"
                SELECT p.id, p.title, (COUNT(parent.title) - 1) AS depth
                FROM posts AS p, posts AS parent
                WHERE p.left BETWEEN parent.left AND parent.right
                GROUP BY p.title
                ORDER BY p.left;
            ";
            using (var reader = cmd.ExecuteReader())
            {
                if (!reader.Read())
                {
                    return null;
                }

                var nodes = new Stack<Post>();
                var scalar = FromDataReader(reader);
                var rootNode = scalar.Post;
                int currentDepth = 0;
                var currentNode = rootNode;
                while (reader.Read())
                {
                    var depth = reader.GetInt32(reader.GetOrdinal("depth"));
                    if (depth > currentDepth)
                    {
                        nodes.Push(currentNode);
                        currentDepth = depth;
                    }
                    else if (depth < currentDepth)
                    {
                        while (depth < currentDepth)
                        {
                            --currentDepth;
                            nodes.Pop();
                        }
                    }
                    scalar = FromDataReader(reader);
                    currentNode = scalar.Post;
                    var p = nodes.Peek();
                    if (p.ChildPosts == null)
                    {
                        p.ChildPosts = new List<Post>();
                    }
                    p.ChildPosts.Add(currentNode);
                }
                nodes.Clear();
                return rootNode;
            }
        }
    }

    private Scalar FromDataReader(DbDataReader reader)
    {
        return new Scalar
        {
            Depth = reader.GetInt32(reader.GetOrdinal("depth")),
            Post = new Post
            {
                PostId = reader.GetInt32(reader.GetOrdinal("id")),
                PostTitle = reader.GetString(reader.GetOrdinal("title"))
            }
        };
    }
}

الآن أن لدينا هذا المخزون يمكن أن نأتي القطع معا:

public class HomeController : Controller
{
    private readonly IPostsRepository _repository;
    public HomeController(IPostsRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Index()
    {
        var post = _repository.GetPost();
        return View(post);
    }
}

و الجزء الأخير هو تكوين المفضلة لديك إطار حقن التبعية لحقن المطلوب تنفيذ مستودع و لأن لدينا واحد فقط حتى الآن من شأنها أن تكون PostsRepositoryAdoNet.و إذا كان الغد كنت ترغب في التبديل إلى ORM كل ما عليك القيام به هو كتابة المقابلة مستودع تنفيذ IPostsRepository واجهة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top