ASP.NET ZERO 学习 —— (18) 应用开发Demo之扩展电话信息
来源:互联网 发布:淘宝三无产品处罚 编辑:程序博客网 时间:2024/05/19 13:45
创建 Phone 实体
现在,在.Core项目中创建一个新的实体,Phone Entity
[Table("PbPhones")]public class Phone : CreationAuditedEntity<long>{ public const int MaxNumberLength = 16; [ForeignKey("PersonId")] public virtual Person Person { get; set; } public virtual int PersonId { get; set; } [Required] public virtual PhoneType Type { get; set; } [Required] [MaxLength(MaxNumberLength)] public virtual string Number { get; set; }}
Phone的数据存储在PbPhones表里,它的主键类型是long。它引用了Person实体作为该电话的所有人。
我们向Person类里添加Phone的集合
[Table("PbPersons")]public class Person : FullAuditedEntity{ public const int MaxNameLength = 32; public const int MaxSurnameLength = 32; public const int MaxEmailAddressLength = 255; [Required] [MaxLength(MaxNameLength)] public virtual string Name { get; set; } [Required] [MaxLength(MaxSurnameLength)] public virtual string Surname { get; set; } [MaxLength(MaxEmailAddressLength)] public virtual string EmailAddress { get; set; } public virtual ICollection<Phone> Phones { get; set; }}
我们还需要一个PhoneType的枚举:
public enum PhoneType : byte{ Mobile, Home, Business}
最后,我们还要向DbContext里添加Phone的DbSet
public virtual IDbSet<Phone> Phones { get; set; }
数据迁移
我们的实体模型被更改,所以我们需要添加一个新的migration:
它会创建一个数据迁移文件来创建PbPhones表:
public partial class Added_Phone : DbMigration{ public override void Up() { CreateTable( "dbo.PbPhones", c => new { Id = c.Long(nullable: false, identity: true), PersonId = c.Int(nullable: false), Type = c.Byte(nullable: false), Number = c.String(nullable: false, maxLength: 16), CreationTime = c.DateTime(nullable: false), CreatorUserId = c.Long(), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.PbPersons", t => t.PersonId, cascadeDelete: true) .Index(t => t.PersonId); } public override void Down() { DropForeignKey("dbo.PbPhones", "PersonId", "dbo.PbPersons"); DropIndex("dbo.PbPhones", new[] { "PersonId" }); DropTable("dbo.PbPhones"); }}
在更新数据库之前,我们可以向数据库添加电话的示例:
public class InitialPeopleCreator{ private readonly AbpZeroTemplateDbContext _Context; public InitialPeopleCreator(AbpZeroTemplateDbContext context) { this._Context = context; } public void Create() { var alistair = this._Context.Persons.FirstOrDefault(p => p.EmailAddress == "alistair.chow@ali.com"); if(alistair == null) { this._Context.Persons.Add( new Entities.Person { Name = "Alistair", Surname = "Chow", EmailAddress = "alistair.chow@ali.com", Phones = new List<Phone> { new Phone {Type=PhoneType.Home, Number="11221122" }, new Phone {Type=PhoneType.Mobile, Number="22332233" } } }); } var tencent = this._Context.Persons.FirstOrDefault(p => p.EmailAddress == "tencent.cloud@ali.com"); if (tencent == null) { this._Context.Persons.Add( new Entities.Person { Name = "Tencent", Surname = "Cloud", EmailAddress = "tencent.cloud@ali.com", Phones = new List<Phone> { new Phone {Type=PhoneType.Home, Number="33443344" } } }); } }}
我们向Alistair添加了两个电话,向Tencent添加了一个电话。但是如果我们现在执行Update-Database,由于人员信息已经存在,所以电话不会被插入。那怎么解决?由于还没有部署,我们可以删除数据库(或truncate People表),再重新创建它。
现在,我们们在程序包管理控制台执行 Update-Database命令。你可以在数据库里看到PbPhones表及里面的数据。
修改GetPeople方法
我们需要修改PersonAppService.GetPeople方法,让返回值里包含电话号码
public ListResultDto<PersonListDto> GetPeople(GetPeopleInput input) { var persons = this._personRepository .GetAll() .Include(p => p.Phones) .WhereIf( !input.Filter.IsNullOrEmpty(), p => p.Name.Contains(input.Filter) || p.Surname.Contains(input.Filter) || p.EmailAddress.Contains(input.Filter) ) .OrderBy(p => p.Name) .ThenBy(p => p.Surname) .ToList(); return new ListResultDto<PersonListDto>(persons.MapTo<List<PersonListDto>>()); }
我们只需要在查询里添加Include 扩展方法,其他代码保持一致。
AddPhone 和 DeletePhone 方法
我们要在IPersonAppService接口里添加两个方法:
Task DeletePhone(EntityDto<long> input);Task<PhoneInPersonListDto> AddPhone(AddPhoneInput input);
我们也可以创建一个IPhoneAppService。但是,我们可以把人看做一个集合,在这里添加电话的相关方法。AddPhoneInput DTO如下所示:
[AutoMapTo(typeof(Phone))]public class AddPhoneInput{ [Range(1, int.MaxValue)] public int PersonId { get; set; } [Required] public PhoneType Type { get; set; } [Required] [MaxLength(Phone.MaxNumberLength)] public string Number { get; set; }}
现在我们实现接口方法:
private readonly IRepository<Entities.Person> _personRepository;private readonly IRepository<Entities.Phone, long> _phoneRepository;public PersonAppService(IRepository<Entities.Person> personRepository, IRepository<Entities.Phone, long> phoneRepository){ this._personRepository = personRepository; this._phoneRepository = phoneRepository;}public async Task DeletePhone(EntityDto<long> input){ await this._phoneRepository.DeleteAsync(input.Id);}public async Task<PhoneInPersonListDto> AddPhone(AddPhoneInput input){ var person = _personRepository.Get(input.PersonId); var phone = input.MapTo<Entities.Phone>(); person.Phones.Add(phone); await CurrentUnitOfWork.SaveChangesAsync(); return phone.MapTo<PhoneInPersonListDto>();}
DeletePhone方法非常简单,只需要通过传入的Id删除对应的Phone。
AddPhone方法首先从数据库中获取Person,再向其添加新的Phone对象,然后进行保存。保存更改会将新添加的电话插入数据库并获取它的ID。因为我们返回的DTO包含了新的电话信息及它的ID。所以,我们在最后一行进行映射。(注意,通常来讲我们一般不会调用CurrentUnitOfWork.SaveChangesAsync。他会在最后的方法中自动调用,当我们需要立即保存实体并获取它的ID时才手动去调用它)
人员列表的编辑模式
最终效果如下:
当我们点击绿色的编辑图标,所选中的行将会扩展显示所有的电话信息。然后我们可以对电话进行删除,或者添加新的电话号码。
视图
视图改变如下:
@using Abp.Web.Mvc.Extensions@using MyCompanyName.AbpZeroTemplate.Web.Navigation@using MyCompanyName.AbpZeroTemplate.Authorization@using MyCompanyName.AbpZeroTemplate.Web.Areas.Mpa.Models.PhoneBook@model MyCompanyName.AbpZeroTemplate.Web.Areas.Mpa.Models.PhoneBook.IndexViewModel@{ ViewBag.CurrentPageName = PageNames.App.Tenant.PhoneBook;}@section Scripts{ @Html.IncludeScript("~/Areas/Mpa/Views/PhoneBook/_CreatePersonModal.js") @Html.IncludeScript("~/Areas/Mpa/Views/PhoneBook/Index.js")}@section Styles{ @Html.IncludeStyle("~/Areas/Mpa/Views/PhoneBook/Index.min.css")}<div class="row margin-bottom-5"> <div class="col-xs-6"> <div class="page-head"> <div class="page-title"> <h1> <span>@L("PhoneBook")</span> </h1> </div> </div> </div> <div class="col-xs-6 text-right"> @if (IsGranted(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)) { <button id="CreateNewPersonButton" class="btn btn-primary blue"> <i class="fa fa-plus"></i>@L("CreateNewPerson") </button> } </div></div><div class="portlet light"> <div class="portlet-title portlet-title-filter"> <h3>@L("AllPeople") (@Model.Items.Count)</h3> <div class="inputs inputs-full-width"> <div class="portlet-input"> <form action="@Url.Action("Index")" method="get"> <div class="input-group"> <input id="FilterPeopleText" name="Filter" value="@Model.Filter" class="form-control" placeholder="@L("SearchWithThreeDot")" type="text" /> <span class="input-group-btn"> <button id="FilterPeopleButton" class="btn default" type="submit"> <i class="icon-magnifier"></i> </button> </span> </div> </form> </div> </div> </div> <div class="portlet-body"> <div id="AllPeopleList" class="list-group"> @foreach (var person in Model.Items) { <a href="javascript:;" class="list-group-item" data-person-id="@person.Id"> <h4 class="list-group-item-heading"> @person.Name @person.Surname <span class="person-buttons"> <button title="@L("Edit")" class="btn btn-circle btn-icon-only green edit-person"> <i class="icon-pencil"></i> </button> @if (IsGranted(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson)) { <button title="@L("Delete", person.Name)" class="btn btn-circle btn-icon-only red delete-person" href="javascript:;"> <i class="icon-trash"></i> </button> } </span> </h4> <p class="list-group-item-text"> @person.EmailAddress </p> <div class="table-scrollable table-phones"> <table class="table table-hover"> <thead> <tr> <th style="width:10%"></th> <th style="width:15%">@L("Type")</th> <th style="width:75%">@L("PhoneNumber")</th> </tr> </thead> <tbody> @foreach (var phone in person.Phones) { @Html.Partial("_PhoneRowInPersonList", new PhoneRowInPersonListViewModel(phone)) } <tr> <td> <button class="btn btn-sm green button-save-phone"> <i class="fa fa-floppy-o"></i> </button> </td> <td> <select name="Type"> <option value="0">@L("PhoneType_Mobile")</option> <option value="1">@L("PhoneType_Home")</option> <option value="2">@L("PhoneType_Business")</option> </select> </td> <td><input type="text" name="Number" /></td> </tr> </tbody> </table> </div> </a> } </div> </div></div>
我们针对每一个Person都添加了一个编辑按钮。然后为每个person添加了一个table用来显示该person的所有电话并允许添加电话。电话列表只有当我们点击了编辑按钮后才会显示,它是通过CSS和JS进行的实现(在后面我们会看见)。
这里有一个重要的思想,我们使用部分视图来显示电话信息,这样做是为了让这部分可以重用。因为我们在新建电话的时候会用到相同的部分视图。_PhoneRowInPersonList 如下所示:
@model MyCompanyName.AbpZeroTemplate.Web.Areas.Mpa.Models.PhoneBook.PhoneRowInPersonListViewModel<tr data-phone-id="@Model.Phone.Id"> <td> <button class="btn btn-sm default button-delete-phone"> <i class="icon-trash"></i> </button> </td> <td>@Model.GetPhoneTypeAsString()</td> <td>@Model.Phone.Number</td></tr>
PhoneRowInPersonListViewModel 如下:
public class PhoneRowInPersonListViewModel{ public PhoneInPersonListDto Phone { get; set; } public PhoneRowInPersonListViewModel(PhoneInPersonListDto phone) { this.Phone = phone; } public string GetPhoneTypeAsString() { return LocalizationHelper.GetString("", "PhoneType_" + Phone.Type); }}
样式
index.less修改如下:
#AllPeopleList { .list-group-item-heading { span.person-buttons { float: right; } } .table-phones{ display: none; } .person-editing{ background-color:#ccffcc; h4{ font-weight:bold; } .table-phones{ display:table; } }}
脚本
添加以下代码至Index.js:
//Edit person button$('#AllPeopleList button.edit-person').click(function (e) { e.preventDefault(); var $listItem = $(this).closest('.list-group-item'); $listItem .toggleClass('person-editing') .siblings().removeClass('person-editing');});//Save phone button$('#AllPeopleList .button-save-phone').click(function (e) { e.preventDefault(); var $phoneEditorRow = $(this).closest('tr'); abp.ajax({ url: abp.appPath + 'Mpa/PhoneBook/AddPhone', dataType: 'html', data: JSON.stringify({ personId: $phoneEditorRow.closest('.list-group-item').attr('data-person-id'), Type: $phoneEditorRow.find('select[name=Type]').val(), Number: $phoneEditorRow.find('input[name=Number]').val() }) }).done(function (result) { $(result).insertBefore($phoneEditorRow); });});//Delete phone button$('#AllPeopleList').on('click', '.button-delete-phone', function (e) { e.preventDefault(); var $phoneRow = $(this).closest('tr'); var phoneId = $phoneRow.attr('data-phone-id'); _personService.deletePerson({ id:phoneId }).done(function () { abp.notify.success(app.localize('SuccessfullyDeleted')); $phoneRow.remove(); });});
当点击修改按钮时,我们通过CSS来控制电话信息的展开和收缩。
在保存按钮的点击事件里,我们 向PhoneBookController的 AddPhone action提交了一个Ajax请求。服务端返回一个插入新号码的HTML,这就是为什么我们使用部分页的原因。
最后,当我们点击删除按钮后会删除该电话信息并在DOM中删除该行。注意这里的事件注册,我们使用了JQuery的On方法,选择器变为激活状态。这意味着,如果我们加入新的元素到页面并且任一元素和选择器匹配,那它的Click事件将被自动绑定。
ADDPHONE ACTION
我们向 PhoneController 添加AddPhone Action:
[HttpPost]public async Task<PartialViewResult> AddPhone(AddPhoneInput input){ PhoneInPersonListDto phoneInPersonList = await this._personAppService.AddPhone(input); var model = new PhoneRowInPersonListViewModel(phoneInPersonList); return PartialView("_PhoneRowInPersonList", model);}
使用PersonAppService.AddPhone并且返回_PhoneRowInPersonList 的部分视图。因此,我们直接将返回值插入到表中。示例返回值如下所示:
<tr data-phone-id="5"> <td> <button class="btn btn-sm default button-delete-phone"> <i class="icon-trash"></i> </button> </td> <td>手机</td> <td>33443344</td></tr>
如你所见,这可以直接插入到table中,就像我们已经做的那样。
- ASP.NET ZERO 学习 —— (18) 应用开发Demo之扩展电话信息
- ASP.NET ZERO 学习 —— (9) 应用开发Demo之工程创建
- ASP.NET ZERO 学习 —— (10) 应用开发Demo之创建实体对象
- ASP.NET ZERO 学习 —— (11) 应用开发Demo之创建应用服务
- ASP.NET ZERO 学习 —— (12) 应用开发Demo之测试应用服务
- ASP.NET ZERO 学习 —— (13) 应用开发Demo之页面呈现Person数据
- ASP.NET ZERO 学习 —— (14) 应用开发Demo之新建People
- ASP.NET ZERO 学习 —— (15) 应用开发Demo之授权
- ASP.NET ZERO 学习 —— (16) 应用开发Demo之删除用户
- ASP.NET ZERO 学习 —— (17) 应用开发Demo之筛选
- ASP.NET ZERO 学习 —— (3) 开发手册之介绍和MVC 应用前端
- ASP.NET ZERO 学习 —— (5) 开发手册之ANGULAR后台单页面应用
- ASP.NET ZERO 学习 —— (6) 开发手册之MVC后台多页面应用及迁移控制台程序
- ASP.NET ZERO 学习 —— (4) 开发手册之AccountController
- ASP.NET ZERO 学习 —— (7) 开发手册之基础架构
- ASP.NET ZERO 学习 —— (8) 开发手册之基于令牌的身份认证&其他
- ASP.NET ZERO 学习 —— (1) 介绍
- ASP.NET ZERO 学习 —— (2) 开始
- 10G向40G网络升级的两种布线方案比较
- I/O多路复用之select
- 深入浅出ES6(十二):代理 Proxies
- Linux开源资源
- SPI总线协议介绍
- ASP.NET ZERO 学习 —— (18) 应用开发Demo之扩展电话信息
- JAVA语言基础第一天学习
- 使用时段:“【周几】【时间】可用”,如“周一到周五全天可用”,“周一、周二14:00-22:00可用”
- 微信小程序开发实战——模块化
- test
- iOS开发之ViewController的生命周期分析和使用
- 商业智能掌控ERP金蝶BI前景被看好的点
- newInstance() 和 new 区别
- ubuntu14.04confluence5.4.4、5.6.6、5.9.4破解版安装