mvc3+ef4.1 Learning Series (10)----MVC+EF processing tree structure

Source: Internet
Author: User
Tags actionlink

Through the previous articles we dealt with one-to-one, a-to-many, many-to-many relationship very well to play the ORM framework for the use of but less about a tree-shaped structure of the processing, and this tree-like relationship we also often encounter, common N-class processing, and often have data and category hooks. Today, we write about how the EF handles the tree structure and how MVC presents the tree structure. The previous examples have been used for an example, and the content is coherent. This article is completely separate ~

First, the common scenarios that you will encounter in your work are addressed to these scenarios.

1. Categories

A. Categories can have unlimited levels

B. The end of the category is not certain that the first level of a node can be two levels other nodes may be to level four

The C.tree model displays the entire category and can crud the tree (can be loaded all at once or asynchronously)

D. breadcrumbs Type Display category

E. Deleting a parent class should remove all of the following subclasses

2. Data linked to categories (this is the article)

A. You can view articles based on any level of category

B. Merging two categories of articles

The above scenarios basically cover the general situation of the category operation if you think there's anything else to deal with, you can tell me I added.

Let's start with the following explanation ~

I. Preparatory work

1. How to create a category entity class to show the tree structure

On the Code

<summary>
Category
</summary>
public class Category
{
<summary>
Primary key
</summary>
public int CategoryId {get; set;}

<summary>
Category name
</summary>
[Required ()]
[Stringlength (5)]
public string CategoryName {get; set;}

<summary>
Parent ID
</summary>
Public nullable<int> ParentID {get; set;}

<summary>
The parent node above
</summary>
Public virtual Category Parent {get; set;}

<summary>
The following child nodes
</summary>
[ForeignKey ("ParentID")]
Public virtual icollection<category> Childkeys {get; set;}

<summary>
Collection of articles for this category
</summary>
Public virtual icollection<article> articlelist {get; set;}

<summary>
Number
</summary>
public string Note {get; set;}


<summary>
State
</summary>
public string State
{
Get
Set
}

<summary>
Level
</summary>
Public nullable<int> Lev
{
Get
Set
}
<summary>
Sort
</summary>
public int Sort
{
Get
Set
}
}

This design is good to show the tree structure a node has a parent class multiple subclasses a category can have multiple articles here, the following four attributes are not necessary ~

2. Article entity class

On the code this better understanding does not explain ~

article entity class

3. Setting up the context

On the Code

public class Treedemocontext:dbcontext
{

Private readonly static string connection_string = "Name=wlfsys_efcf_connstring";

Public dbset<category> Category {get; set;}
Public dbset<article> article {get; set;}

Public Treedemocontext ()
: Base (connection_string)
{
This. configuration.proxycreationenabled = false;
}


protected override void Onmodelcreating (Dbmodelbuilder modelBuilder)
{
Modelbuilder.conventions.remove<pluralizingtablenameconvention> ();//contract for removing plural table names
}
}

There is no need to use the fluent API to map the relationship between the entity class and the database there is no bright spot (in fact, I always want to know how to use the Fluent API map to solve the following problems have to know the expert pointing under ~ ~ Gratitude)

4. Database initialization

This is my way of dealing with the tree structure with EF The most critical point is that people who are skilled in using EF look at me. The creation of the category entity class above will find this to be wrong because it creates a self-referential view of the resulting database table structure

The INSERT statement conflicts with the FOREIGN KEY same TABLE constraint "Category_childkeys" because of a self-referencing insert.

My workaround is to delete this foreign KEY constraint code when initializing the database

public class Treedemoinitializer:dropcreatedatabaseifmodelchanges<treedemocontext>
{
protected override void Seed (Treedemocontext context)
{
Delete Association
Context. Database.executesqlcommand ("ALTER TABLE [dbo].[ Category] DROP CONSTRAINT [Category_childkeys] ");


ID must be added
var Category = new list<category>
{
New category{categoryid=1, categoryname= "Asia", Lev=1, Parentid=0, note= "001", Childkeys=new list<category>{
New Category{categoryid=2,categoryname= "China", lev=2,note= "00101", childkeys=new list<category>{new Category{ Categoryid=6, Categoryname= "Henan", Lev=3, note= "0010101"},new category{categoryid=7, Categoryname= "Guangzhou", Lev=3, Note= " 0010102 "}},
New Category{categoryid=3,categoryname= "Japan", lev=2,note= "00102", childkeys=new list<category>{new Category{ Categoryid=8, Categoryname= "Japan Province 1", Lev=3, note= "0010201"},new category{categoryid=9, Categoryname= "Japan 2", Lev=3, Note = "0010202"}}
} }
},
New Category {categoryid=4, categoryname= "Europe", Lev=1, Parentid=0, note= "002", Childkeys=new list<category>{
New Category{categoryid=5,categoryname= "Holland", lev=2,note= "00201"}
} }

};
Category.foreach (c = context. Category.add (c));



var articles = new list<article>{

New article{Articlename= "novel", Createtime=datetime.now, categoryid=5},
New article{Articlename= "novel", Createtime=datetime.now, categoryid=5},
New article{Articlename= "novel", Createtime=datetime.now, categoryid=5},
New Article{articlename= "novel 1", Createtime=datetime.now, categoryid=6},
New article{Articlename= "novel 2", Createtime=datetime.now, categoryid=6},
New article{Articlename= "novel 3", Createtime=datetime.now, categoryid=6},
New article{articlename= "novel 4", Createtime=datetime.now, categoryid=7},
New article{articlename= "novel 5", Createtime=datetime.now, categoryid=7},
New article{Articlename= "novel 6", Createtime=datetime.now, categoryid=7},
New article{Articlename= "novel 7", Createtime=datetime.now, categoryid=8},
New article{Articlename= "novel 8", Createtime=datetime.now, categoryid=8},
New article{articlename= "novel 9", Createtime=datetime.now, categoryid=8},
New article{Articlename= "novel", Createtime=datetime.now, categoryid=9},
New article{Articlename= "novels one by One", Createtime=datetime.now, categoryid=9},
New article{Articlename= "novel", Createtime=datetime.now, categoryid=9}

};
Articles.foreach (A = context). Article.add (a));

Context. SaveChanges ();
}
}

and initialize some of the data into this initialization is the addition of the category to a small problem when added to our database category ID is self-growing by default it is not necessary to specify the primary key ID, but do not specify the ID as I insert the next time I insert more than an error ~ ~ cannot be determined "contosouniversi Ty. DAL. Category_childkeys "The principal side of the relationship. Multiple entities added may have the same primary key. The ID was specified to solve the problem

5. Building the basic project structure

Still using unit of work +repository (project big words to join IService, Service plus IOC, here is just a simple demo)

Two. About the operation of the category and the display

Model 1.tree shows the entire category

It's easy to implement the tree display in the Webfrom era because we have sharp controls. The TreeView control is added with a recursive binding, which is a very simple thing to do. This is a webfrom benefit, but it's also a bad place. For example, the TreeView generates table nested t Able if I want to change to UL Li how to do control development caused by the coupling over high digression said more return to the topic ~

Here I have two ways to achieve the TreeView display

A method extends a HtmlHelper

Implements HTML. Tree (category) to show the TreeView

Say a few words before using this method. Because it's kind of like using controls, the code and the view are still together. The second place I used recursion, but the small project is no problem directly on the code

    public static mvchtmlstring Tree (this htmlhelper html, Category TreeModel)
{
Return Bindtree (TreeModel);
}

private static mvchtmlstring Bindtree (Category TreeModel)
{
StringBuilder sb = new StringBuilder ();
if (TreeModel! = null)
{
Sb. Append ("<ul>");

list<category> list = TreeModel.ChildKeys.ToList ();
foreach (var item in list)
{
Sb. Append ("<li>");
Sb. Append (item. CategoryName);
Sb. Append ("</li>");
Sb. Append (Bindtree (item));
}
Sb. Append ("</ul>");

}
Mvchtmlstring MSTR = new mvchtmlstring (sb.) ToString ());
Return MSTR;
}

The above implementation of the most simple display tree structure is simply recursive use of this can expand whether to display a checkbox ah up the default show a few levels ah, and so on the back of the connection Ah on~~

B. Using AJAX to implement asynchronous loading (personal favorite method) the previous implementation of the diagram I did not do any art look very difficult to see ~ everyone will see

There is a small arrow in front of you can open ~ ~ Turn on the open State ~

Below the view explanation and thinking directly added to the inside

<script type= "Text/javascript" >
$(
function () {
var Clickli = function () {
$ (this). Children ("ul"). Toggle (); Toggle Hide and show the ul below Li


Toggle whether the IMG icon is selected or unchecked
if ($ (this). Children ("img"). attr ("src") = = "Http://www.cnblogs.com/Content/img/selectNode.jpg") {

$ (this). Children ("img"). attr ("src", "http://www.cnblogs.com/Content/img/noselectNode.jpg");
}
else {
$ (this). Children ("img"). attr ("src", "http://www.cnblogs.com/Content/img/selectNode.jpg");
}


When do I send a request to load the following node?
There is a node under the IMG attribute that is not empty because there is no img tree with no nodes and his UL number below is 0
if ($ (this). Children ("img"). attr ("src")! = undefined && $ (this). Children ("ul"). Length = = 0) {
var cid = $ (this). attr ("id");
var li = $ (this);
$.post ("Getcategorybyid", {id:cid}, function (data) {

if (data = = "-1") {
Alert ("failure");
}
else {
Li.append (data);
}
});
}
return false;
}

Why not use live directly click?

Because the Click event loaded by the AJAX request is not working, use live to ~ ~ Remember
$ ("#CategoryTree Li"). Live ("Click", null, Clickli);
}
);

</script>


<p>
@Html. ActionLink ("Create New", "create")
</p>

@* @Html. Tree (Model); *@

<ul id= "CategoryTree" >
@foreach (var item in Model.childkeys)
{
<li id= "@item. CategoryId ">
@if (item. Childkeys.count > 0)
{

}
<span class= "Name" > @item. Categoryname</span>
@Html. ActionLink ("Add", "Create", new {[email protected]})
@Html. ActionLink ("Modify", "edit", new {[email protected]})
</li>
}
</ul>

Here is the jquery Ajax request when we often return to JSON and then build here next to mvc another way to return a partial view ~ ~ I like this way code~ not explain ~

Ajax Returns partial view Code

view of partial views

2. Show breadcrumbs

The display of the tree structure we often encounter the TreeView type and also encounter another kind of breadcrumbs such as

What we're going to do here is to push up a layer up to the top of the current category and make the last bold display ~ My idea is this, for example, the smallest canton in the current category is pushed to the top of the hierarchy by recursion to get Guangzhou > China > Asia by reversing the string and giving it a bold line. ~ ~ Code as follows

<summary>
Build bread crumbs According to the current category
</summary>
<returns></returns>
public static mvchtmlstring Menu (this htmlhelper html, Category TreeModel)
{

return new Mvchtmlstring (Menureverse (Bindmenu (TreeModel));
}

<summary>
Recursive calls to get Guangzhou > China > Asia
</summary>
<returns></returns>
private static string Bindmenu (Category Model)
{
StringBuilder sb = new StringBuilder ();
Sb. Append (Model.categoryname);
if (model.parent! = null)
{
Sb. Append (">");
Sb. Append (Bindmenu (model.parent));
}
Return SB. ToString ();
}

<summary>
Invert the string and give the last word a bold label
</summary>
<returns></returns>
private static string Menureverse (String menu)
{
return string. Join (">", Menu. Split (' > '). Select ((s, i) = = i = = 0? string. Format ("<strong>{0}</Strong>", s): s). Reverse (). ToArray ());
}

3. Delete the parent class to remove all of the following subclasses

Here's an important way to get a tree structure. The collection of IDs for all subclasses of the class by the current class is then deleted with the delete in (subclass collection) on the line ~ ~ Forgot how to directly execute the SQL statement ~ ~ to look at an article. Here's how to get the next face class collection by now

  <summary>
Get a collection of all subclasses under the parent class
</summary>
<returns></returns>
Private list<int> getcidbypid (int pid)
{
list<int> cidlist = new list<int> ();
Category Categorymodel = UnitOfWork.CategoryRepository.GetTEntityByID (PID);
foreach (var item in Categorymodel.childkeys)
{
Cidlist.add (item. CATEGORYID);
}

foreach (var item in Categorymodel.childkeys)
{
Cidlist.addrange (Getcidbypid (item. CATEGORYID));
}
return cidlist;

Get 1,2,3,4,5 tring strcid= string. Join (",", cidlist);
}

Still gets all the child node collections by recursion and then through string. Join (",", cidlist) gets what is needed in the delete in ().

Three. Presentation of data linked to categories

I. Can view articles based on categories of any level

Still available in two ways ~

1. Query articles by category using recursion

But this efficiency is too tangled up ~ ~

<summary>
Get all of the following articles from any category
</summary>
<param name= "CID" ></param>
<returns></returns>
Private list<article> getarticlebycid (int cid)
{
List<article> articlelist=new list<article> ();
Category Categorymodel=unitofwork.categoryrepository.gettentitybyid (CID);
if (CategoryModel.ChildKeys.Count = = 0)
{
Articlelist.addrange (CategoryModel.articleList.ToList ());
}

foreach (var item in Categorymodel.childkeys)
{
Articlelist.addrange (Getarticlebycid (item. CATEGORYID));
}
return articlelist;

}

2. Using the ID set of all subclasses of the class by the current class, and so on.

Here's a little knowledge ~ Execute SQL in with LINQ ~ with contains the code is as follows

    Public ActionResult Index ()
{
Prepare test data test for different scenarios getcidbypid to get a collection of all subclasses and sub-subclasses, etc. by ID
Test the superlative
list<int> cidlist = getcidbypid (1);

var cidlist = getcidbypid (2);

Test the lowest level
var cidlist = getcidbypid (6);

Greedy load category in order to show category names ~
var articlelist = UnitOfWork.ArticleRepository.Get (c = cidlist.contains (C.categoryid), includeproperties: " Category ");
Return View (articlelist);
}

Two. Merging two categories of articles

This is very simple ~ Merging two classes is to change the ID of the article under one class to another meaning that batch operations do not use the EF update on the line is too slow ~ also to send multiple update statements

Use the context. Database.sqlquery execute update directly this will not write code ~

Four. Telerik more cool display tree with third-party tools

What I've written above is a little fun. There are many places that are imperfect and irrational, and MVC implements tree third-party tools already have the very best to help us.

Here we recommend an open source is the Telerik tree------Introduction and connection

Basically all of the operations are encapsulated in the inside of the ~ very convenient and there are many other controls ~

Also, recommend that you look at the source of third-party tools must be more to see the implementation do not just use

Five. Summary

This is completely independent and the previous few does not matter ~ The code stick is the core fragment ~ Smart people to see it and should have a better implementation

I would like to share with you the experience of the EF MVC process tree and the problems encountered.

I also ask a question because many of the tree structures are used for recursion. I think there will be some problems in the process of high concurrency and large data processing in EF I hope you can talk about how to solve

The overall content is not too much difficulty ~ Everybody knocks on the practice

Really lazy classmate leave an e-mail I send the demo to you ~

mvc3+ef4.1 Learning Series (10)----MVC+EF processing tree structure

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.