惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
TaoSecurity Blog
TaoSecurity Blog
H
Heimdal Security Blog
Help Net Security
Help Net Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
V2EX - 技术
V2EX - 技术
博客园 - 【当耐特】
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Secure Thoughts
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
有赞技术团队
有赞技术团队
S
Schneier on Security
S
SegmentFault 最新的问题
Google Online Security Blog
Google Online Security Blog
H
Hacker News: Front Page
The Last Watchdog
The Last Watchdog
Schneier on Security
Schneier on Security
PCI Perspectives
PCI Perspectives
IT之家
IT之家
Project Zero
Project Zero
博客园 - 司徒正美
P
Privacy International News Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Jina AI
Jina AI
Security Latest
Security Latest
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
NISL@THU
NISL@THU
Webroot Blog
Webroot Blog
N
Netflix TechBlog - Medium
L
Lohrmann on Cybersecurity

博客园 - Kevin Lin

Happy New Year! HTTP状态码大全 [转]jquery的一个模板引擎-zt - Kevin Lin - 博客园 2009年3月 2008年9月-10月 跟ASP.NET MVC一起使用jQuery [摘自千寻网]给鼠标右键增加“见好就收”的功能 ASP.NET 2.0中的URL映射 在.net中使用Gmail发送邮件 [绝对原创]从VS2003(.net1.1)升级到vs2005(.net2.0)全程跟踪记录 使用Asp.net mvc + Linq + mvc_scaffold_gen_setup.exe 生成一个完整的家庭帐册大管家程序 之三 2008年4月-5月 使用Asp.net mvc + Linq + mvc_scaffold_gen_setup.exe 生成一个完整的家庭帐册大管家程序 之一 XNA Game Studio 2.0 Released版 发布了,好像是前几天的事,但园子里似乎没有讯息嘛 向大家推荐一个不错的休闲游戏 VS2003(.net framework1.1)中,如果让日历控件的“星期”去掉? 农历js脚本 - Kevin Lin - 博客园 WEB开发碰到的问题及经验十八则 - Kevin Lin - 博客园 根据分辨率不同调用不同的css文件 - Kevin Lin - 博客园
使用Asp.net mvc + Linq + mvc_scaffold_gen_setup.exe 生成一个完整的家庭帐册大管家程序 之二
Kevin Lin · 2008-04-16 · via 博客园 - Kevin Lin

[前言]
前几天发过一篇blog:使用Asp.net mvc + Linq + mvc_scaffold_gen_setup.exe 生成一个完整的家庭帐册大管家程序 之一 
在第一篇blog中,展示了使用Mvc_Scaffold_gen_setup.exe生成的Mvc代码,包括其中的一些错误。
隔了几天,我把生成的代码重新整理下,并加些数据进去做测试。发现了几个问题(稍后列出问题),想在这里向各位咨询。

[业务介绍]
写这个程序的初衷是为了熟悉Asp.net MVC,正好要给自己写一个家庭帐务管理的小程序。我想尽可能简单化所有的业务需求,尽量不涉及专业的业务,另外,后期考虑增加帐务预估和报表反馈等功能。
下面介绍下示例中的家庭帐册大管家的业务需求及数据结构:
顾名思义,就是辅助记帐。目前的功能模块有:
1、收入,对应的数据模型是Income;
2、支出,对应的数据模型是Expense;
3、借还,对应的数据模型是AttachAccount;
4、帐务管理,对应的数据模型是Account;
5、帐务分类管理,包括大类和小类,对应的数据模型分别是PrimaryClass和ChildClass;
6、转账,对应的数据模型是TranferAccount;
7、家庭成员管理,对应的数据模型是Member。
下面见数据模型图,是从解决方案AccountBookDB.dbml截图来的。

[代码说明]
供下载的程序中,各个数据库可以进行增、删、改。但这些功能都是mvc_scaffold_gen_setup.exe这个工具之前生成的。(关于本工具生成的代码中存在的问题,请见之一
但是,在这里我希望把大家的注意力放在以下这个部分:
1、Controllers/ChildClassController.cs
2、Views/ChildClass/Add.aspx、Edit.aspx、List.aspx
注:本文要说明的内容都是这几个文件相关的部分,其余的模块后续介绍。

[操作步骤]
下面从生成数据库开始详细介绍,直到本文为止的最新内容及发现的问题。
1、打开“开始”、“程序”、Microsoft Sql Server 2005 、SQL Server Management Studio Express。
2、新建数据库AccountBookDB,路径自己选择,把下载回来的压缩包中的AccountBookDB.sql执行一下,数据库就建好了。
3、打开VS2008 (我用的是英文版),应该没什么区别。新建一个Asp.net mvc web Application,取名“AccountBook”,暂时不选单元测试的项目。
4、在项目中连接数据库,把AccountBookDB连接进来。
5、在解决方案的Model文件夹中,添加一个Linq to Sql Classes,命名为AccountBookDB.dbml。然后在VS2008的Server Explorer中,把AccountBookDB所有表一次性拉到AccountBookDB.dbml的左边的空白处。就会出现上面的那张数据库模型图。
6、默认已安装mvc_scaffold_gen_setup.exe(该工具下载地址,搜下园子里的blog),打开它(Mvc Scaffold Generator),第一行的Dbml File选择前面建好的AccountBookDB.dbml;第二行的NameSpace保持默认值。第三行选择生成的文件存放路径,这里选择之前新建的解决方案所在路径。Select All Tables 可不选。
7、在解决方案中把第6步生成的文件Include in Project.
8、修改代码中的一个错误:
 View/PrimaryClass/Add.aspx中:第25行的“<%=Item.IsAdmin== true ? "checked= true":""%>”,其中的IsAdmin错误,我们的数据模型中可没有这个字段。PrimaryClass这个表中有一个字段ClassType(意思是该分类属于收入还是支出),是bit类型,该工具错误地当作IsAdmin了。我把它修改为“ClassType;同样View/PrimaryClass/Edit.aspx中的IsAdmin同样需要修改。
9、便于调试,我们在Site.Master的第22行增加了如下代码,生成几个链接。

<li>
                    
<%= Html.ActionLink("Account""List""Account"%></li>
                
<li>
                    
<%= Html.ActionLink("AttachAccount""List""AttachAccount")%></li>
                
<li>
                    
<%= Html.ActionLink("ChildClass""List""ChildClass")%></li>
                
<li>
                    
<%= Html.ActionLink("PrimaryClass""List""PrimaryClass")%></li>
                
<li>
                    
<%= Html.ActionLink("Expense""List""Expense")%></li>
                
<li>
                    
<%= Html.ActionLink("Income""List""Income")%></li>
                
<li>
                    
<%= Html.ActionLink("TranferAccount""List""TranferAccount")%></li>
                
<li>
                    
<%= Html.ActionLink("Member""List""Member")%></li>

10、编译,运行,增加一些数据,或者下载我的数据库备份:点击下载

[修改代码]
好,以上的程序都能正常运行,现在来看这个模块:

http://localhost:19374/ChildClass/Add (前面的19374端口可能有变,自己修改)
输入ChildClassName和PrimaryClassID,很显然,这里的PrimaryClassID不够人性化,还不能做到Html下拉框的方式。
于是我们作如下修改:
    1)在Models中增加类文件ChildClassViewData.cs,里面包含两个类:ChildClassEditViewDataChildClassNewViewData,代码如下:

namespace AccountBook.Models
{
    
public class ChildClassEditViewData
    
{
        
public ChildClassInfo ChildClass getset; }
        
public List<PrimaryClassInfo> PrimaryClassList getset; }
    }


    
public class ChildClassNewViewData
    
{
        
public List<PrimaryClassInfo> PrimaryClassList getset; }
    }
 
}

    2)然后打开ChildClassController.cs,修改其中的Add()方法为:

     public void Add()
        
{
            ChildClassNewViewData viewData 
= new ChildClassNewViewData();
            viewData.PrimaryClassList 
= DBContext.GetPrimaryClassList();
            RenderView(
"Add", viewData);
        }

    这里是获取了PrimaryClassList,保存在ChildClassNewViewData的实例中,然后RenderView到Add.aspx,这样,在Add.aspx.cs中,页面继承自ViewPage<ChildClass>必须修改为ViewPage<ChildClassNewViewData>,这样在Add.aspx这个视图部分,ViewData代表的就是强类型的ChildClassNewViewData对象。
    3)打开Views/ChildClass/Add.aspx,可以看到,提供输入PrimaryClassID的是一个<input type="text"......>

<input type="text" name="PrimaryClassID" id="PrimaryClassID" value="<%= Item.PrimaryClassID%>" />

    现在我们就可以将其修改为:

<%=Html.Select("PrimaryClassID", ViewData.PrimaryClassList) %>

    使用的是HtmlHelp中的Select重载方法来绑定下拉框。“PrimaryClassID”是控件名称,第二个参数是数据源。
    同样,在Views/ChildClass/Edit.aspx中,我们同样将相关代码

<input type="text" name="PrimaryClassID" id="PrimaryClassID" value="<%= Item.PrimaryClassID%>" />

    替换为如下:

<%=Html.Select("PrimaryClassID", Item.PrimaryClassList, Item.ChildClassInfo.PrimaryClassID) %>

    在Edit.aspx页面,显示出当前ChildClass所对应的PrimaryClassID,也是以下拉框的形式表示,同时默认选择PrimaryClassID对应的PrimaryClassName,各参数含义同上,第三个参数就是默认选择的PrimaryClassID。
    4)好,现在打开Views/ChildClass/List.aspx页面,显示了当前所有ChildClass,我们看下这部分的代码:

<h2>ChildClass List   <%=    Html.ActionLink("Add","Add" ) %>    </h2>   
    
<% AccountBookTest.Models.ChildClassList Lst = ViewData; %> 
    
<%
        
if (ViewContext.TempData["msg"!= null)
        
{         
    
%>
        
<p><%=ViewContext.TempData["msg"%></p>
    
<%
        }
    
    
%>            
    
<form>
      
<table>
            
            
<tr>
                
<td><strong>ChildClassName</strong></td>
                
<td><strong>PrimaryClassID</strong></td>
            
</tr>
            
<%foreach (AccountBookTest.Models.ChildClass item in Lst) %>
            
<%{%>
            
<tr>
                
<td><%=item.ChildClassName.ToString()%></td>
                
<td><%=item.PrimaryClassID.ToString()%></td>
                
<td><%=Html.ActionLink("Edit","Edit",new {id = item.ChildClassID})%></td>
                
<td><%=Html.ActionLink("Delete","Delete"new {id = item.ChildClassID})%></td>
            
</tr>
            
<%}
%>
            
      
</table>
      
<p></p>
    
</form>

    可以看到,有一个很亲切的c#代码foreach语句出现,它的作用是循环当前的AccountBookTest.Models.ChildClassList Lst,逐一显示ChildClass的信息:ChildClassName,PrimaryClassID以及两个可选操作Edit和Delete。
    现在我们进行如下修改:

<h2>
        ChildClass List
        
<%=Html.ActionLink("Add","Add" ) %>
    
</h2>
    
<% AccountBook.Models.ChildClassList Lst = ViewData; %>
    
<%
        
if (ViewContext.TempData["msg"!= null)
        
{         
    
%>
    
<p>
        
<%=ViewContext.TempData["msg"%></p>
    
<%
        }
    
    
%>
    
<table>
        
<tr>
            
<td>
                
<strong>ChildClassName</strong>
            
</td>
            
<td>
                
<strong>PrimaryClass</strong>
            
</td>
            
<td>
                
<strong>Edit</strong>
            
</td>
            
<td>
                
<strong>Delete</strong>
            
</td>
        
</tr>
        
<asp:Repeater ID="AllChildClass" runat="server" 
            onitemdatabound
="AllChildClass_ItemDataBound">
            
<ItemTemplate>
                
<tr>
                    
<td>
                        
<%# Eval("ChildClassName"%>
                    
</td>
                    
<td>
                        
<%# Eval("PrimaryClassID"%>
                    
</td>
                    
<td>
                        
<asp:HyperLink ID="hlEdit" runat="server">Edit</asp:HyperLink>
                    
</td>
                    
<td>
                        
<asp:HyperLink ID="hlDelete" runat="server">Delete</asp:HyperLink>
                    
</td>
                
</tr>
            
</ItemTemplate>
        
</asp:Repeater>
    
</table>

    用一个服务器端控件Reapter绑定ChildClassList.因此,List.aspx.cs中的代码修改为如下:

public partial class ChildClassListView : ViewPage<ChildClassList>
    
{
        
protected System.Web.UI.WebControls.Repeater AllChildClass;//这里居然要声明下控件(下同),否则在codefile中无法访问Reapter控件?困惑!
        
protected System.Web.UI.WebControls.HyperLink hlEdit;
        
protected System.Web.UI.WebControls.HyperLink hlDelete;

        
public void Page_Load()
        
{
            AllChildClass.DataSource 
= ViewData;//这里绑定的数据源就是ChildClassList实例对象。
            AllChildClass.DataBind();
        }


        
protected void AllChildClass_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
        
{
            
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            
{
                ChildClassInfo childClassInfo 
= (ChildClassInfo)e.Item.DataItem;

                HyperLink hlEdit 
= (HyperLink)e.Item.FindControl("hlEdit");
                HyperLink hlDelete 
= (HyperLink)e.Item.FindControl("hlDelete");
                hlEdit.NavigateUrl 
= "http://www.cnblogs.com/ChildClass/Edit/" + childClassInfo.ChildClassID;
                hlDelete.NavigateUrl 
= "http://www.cnblogs.com/ChildClass/Delete/" + childClassInfo.ChildClassID;
            }

        }

    }

    现在我的问题来了:
    1)页面上使用的服务器端控件Reapter,在CodeFile中居然必须声明,否则无法识别,为什么会这样?所有服务器控件都必须声明,我之前看的一个例子就没有,怎么回事?麻烦各位帮我找找原因。
    [2008.04.17晚回答]在解决方案上右键——>Convert to Web Applications就可以把解决方案变成Web Application的形式。这一个Convert其实就是给每个页面(比如Test.aspx)增加对应的Test.designer.cs的文件,然后页面上的控件的声明全部放在这里。其实这个答案应该早就想到,只是太专注于MVC,反而忘了根本的web Application文件结构。
    2)在修改之前的页面代码中的foreach语句,可以使用<%=Html.ActionLink("Edit","Edit",new {id = item.ChildClassID})%>来很方便很直接地放置一个Edit链接,链接地址是ChildClass/Edit/[ChildClassID],
    现在问题是,我使用了Reapter控件直接绑定数据源之后,怎样才可以类似<%=Html.ActionLink("Edit","Edit",new {id = item.ChildClassID})%>这样的写法,直接生成一个Edit的链接呢?疑惑在于,在Reapter中无法把[ChildClassID]传到<%=Html.ActionLink("Edit", "Edit", ……)%>中的"……"中。
    怎么办?我暂时只能采用webForm的做法,在ItemBound事件中动态绑定......那请问,是我的做法有错误还是本身就不能通过服务器控件绑定的方式来动态生成Edit按钮?
    ps:Delete的也是同样问题。
    3)2008.04.17补充一个问题:显示ChildClass信息的时候,由于Model.ChildClassInfo中仅有PrimaryClassID属性 ,但如果要显示出PrimaryClassID对应的PrimaryClassName,那该如何实现?在Model.ChildClassInfo中增加PrimaryClassName属性??还是在Controllers中进行匹配?补充:这其实是类设计的范畴,和mvc没多大关系的。

总结:今天的blog就写这些内容,就是ChildClass的Add和Edit,以及List的显示。同时提了个问题,留给大家帮我解决。

本文最新Demo下载地址是:AccountBook.rar(最新)  
以及数据库的备份(含数据):AccountBookDB.rar