zoukankan      html  css  js  c++  java
  • Orchard:处理1对多的关系

        建立个人通讯内容时,从一个城市列表中下拉选择所在城市是非常普通的一个应用,这就是1-n的关系,本篇介绍Orchard如何支持1对多的关系。这里我们建立一个Address part,它将用在一个Customer content type中。The address part有address、zip code、city name、state。这个state和city将是一个1-n关系。

        本篇将不再介绍如何建立Model,不清楚地可以查看之前写的Orchard:把之前写的Map Content Part专为一个Widget来使用

    给address part生成模型

    以下为Address model的代码

    View Code
    using Orchard.ContentManagement;
    using Orchard.ContentManagement.Records;

    namespace RelationSample.Models
    {
    public class StateRecord
    {
    public virtual int Id { get; set; }
    public virtual string Code { get; set; }
    public virtual string Name { get; set; }
    }

    public class AddressPartRecord : ContentPartRecord
    {
    public virtual string Address { get; set; }
    public virtual string City { get; set; }
    public virtual StateRecord StateRecord { get; set; }
    public virtual string Zip { get; set; }
    }

    public class AddressPart : ContentPart<AddressPartRecord>
    {
    public string Address
    {
    get { return Record.Address; }
    set { Record.Address = value; }
    }
    public string City
    {
    get { return Record.City; }
    set { Record.City = value; }
    }
    public StateRecord State
    {
    get { return Record.StateRecord; }
    set { Record.StateRecord = value; }
    }
    public string Zip
    {
    get { return Record.Zip; }
    set { Record.Zip = value; }
    }
    }
    }

    生成数据库表和part

    View Code
    using System;
    using System.Collections.Generic;
    using System.Data;
    using Orchard.ContentManagement.Drivers;
    using Orchard.ContentManagement.MetaData;
    using Orchard.ContentManagement.MetaData.Builders;
    using Orchard.Core.Contents.Extensions;
    using Orchard.Data.Migration;
    using Orchard.Data;
    using RelationSample.Models;

    namespace RelationSample
    {
    public class Migrations : DataMigrationImpl
    {
    public int Create()
    {
    SchemaBuilder.CreateTable(
    "AddressPartRecord",
    table
    => table
    .ContentPartRecord()
    .Column
    <string>("Address")
    .Column
    <string>("City")
    .Column
    <int>("StateRecord_Id")
    .Column
    <string>("Zip")
    );

    SchemaBuilder.CreateTable(
    "StateRecord",
    table
    => table
    .Column
    <int>("Id", column => column.PrimaryKey().Identity())
    .Column
    <string>("Code", column => column.WithLength(2))
    .Column
    <string>("Name")
    );

    ContentDefinitionManager.AlterPartDefinition(
    "AddressPart",
    builder
    => builder.Attachable());

    return 1;
    }

    private readonly IRepository<StateRecord> _stateRepository;

    public Migrations(IRepository<StateRecord> stateRepository)
    {
    _stateRepository
    = stateRepository;
    }

    private readonly IEnumerable<StateRecord> _states =
    new List<StateRecord> {
    new StateRecord {Code = "AL", Name = "Alabama"},
    new StateRecord {Code = "AK", Name = "Alaska"},
    new StateRecord {Code = "WS", Name = "Western Australia"},
    new StateRecord {Code = "...", Name = "Other"},
    };

    public int UpdateFrom1()
    {
    if (_stateRepository == null)
    throw new InvalidOperationException("Couldn't find state repository.");
    foreach (var state in _states)
    {
    _stateRepository.Create(state);
    }
    return 2;
    }

    }
    }
    系统可以自动识别外键, StateRecord_Id这个字段类型为StateRecord类的Id属性类型。

    添加handler

    这里没什么特殊的,和以前介绍的构建module一样:

    View Code
    using Orchard.Data;
    using Orchard.ContentManagement.Handlers;
    using RelationSample.Models;

    namespace RelationSample.Handlers
    {
    public class AddressPartHandler : ContentHandler
    {
    public AddressPartHandler(IRepository<AddressPartRecord> repository)
    {
    Filters.Add(StorageFilter.For(repository));
    }
    }
    }

    The address service class

    Address服务类依赖于state repository,这样就可以获得states列表。

    View Code
    using System.Collections.Generic;
    using System.Linq;
    using Orchard;
    using Orchard.ContentManagement;
    using Orchard.Data;
    using RelationSample.Models;
    using RelationSample.ViewModels;

    namespace RelationSample.Services
    {
    public interface IAddressService : IDependency
    {
    void UpdateAddressForContentItem(
    ContentItem item, EditAddressViewModel model);
    IEnumerable
    <StateRecord> GetStates();
    }

    public class AddressService : IAddressService
    {
    private readonly IRepository<StateRecord> _stateRepository;

    public AddressService(IRepository<StateRecord> stateRepository)
    {
    _stateRepository
    = stateRepository;
    }

    public void UpdateAddressForContentItem(
    ContentItem item,
    EditAddressViewModel model)
    {

    var addressPart
    = item.As<AddressPart>();
    addressPart.Address
    = model.Address;
    addressPart.City
    = model.City;
    addressPart.Zip
    = model.Zip;
    addressPart.State
    = _stateRepository.Get(
    s
    => s.Code == model.StateCode);
    }

    public IEnumerable<StateRecord> GetStates()
    {
    return _stateRepository.Table.ToList();
    }
    }
    }

    建立一个ViewModel

    当在前端显示时,我们把part的所有属性都显示出来,包括state的code和name。我们现在需要建立一个ViewModel

    View Code
    using System.Collections.Generic;
    using RelationSample.Models;

    namespace RelationSample.ViewModels
    {
    public class EditAddressViewModel
    {
    public string Address { get; set; }
    public string City { get; set; }
    public string StateCode { get; set; }
    public string StateName { get; set; }
    public string Zip { get; set; }
    public IEnumerable<StateRecord> States { get; set; }
    }
    }

    添加driver

    添加AddressPartDriver:

    View Code
    using JetBrains.Annotations;
    using Orchard.ContentManagement;
    using Orchard.ContentManagement.Drivers;
    using RelationSample.Models;
    using RelationSample.Services;
    using RelationSample.ViewModels;

    namespace RelationSample.Drivers
    {
    [UsedImplicitly]
    public class AddressPartDriver : ContentPartDriver<AddressPart>
    {
    private readonly IAddressService _addressService;

    private const string TemplateName = "Parts/Address";

    public AddressPartDriver(IAddressService addressService)
    {
    _addressService
    = addressService;
    }

    protected override string Prefix
    {
    get { return "Address"; }
    }

    protected override DriverResult Display(
    AddressPart part,
    string displayType,
    dynamic shapeHelper)
    {

    return ContentShape("Parts_Address",
    ()
    => shapeHelper.Parts_Address(
    ContentPart: part,
    Address: part.Address,
    City: part.City,
    Zip: part.Zip,
    StateCode: part.State.Code,
    StateName: part.State.Name));
    }

    protected override DriverResult Editor(
    AddressPart part,
    dynamic shapeHelper)
    {

    return ContentShape("Parts_Address_Edit",
    ()
    => shapeHelper.EditorTemplate(
    TemplateName: TemplateName,
    Model: BuildEditorViewModel(part),
    Prefix: Prefix));
    }

    protected override DriverResult Editor(
    AddressPart part,
    IUpdateModel updater,
    dynamic shapeHelper)
    {

    var model
    = new EditAddressViewModel();
    updater.TryUpdateModel(model, Prefix,
    null, null);

    if (part.ContentItem.Id != 0)
    {
    _addressService.UpdateAddressForContentItem(
    part.ContentItem, model);
    }

    return Editor(part, shapeHelper);
    }

    private EditAddressViewModel BuildEditorViewModel(AddressPart part)
    {
    var avm
    = new EditAddressViewModel
    {
    Address
    = part.Address,
    City
    = part.City,
    Zip
    = part.Zip,
    States
    = _addressService.GetStates()
    };
    if (part.State != null)
    {
    avm.StateCode
    = part.State.Code;
    avm.StateName
    = part.State.Name;
    }
    return avm;
    }
    }
    }

    建立视图

    • 前端

    新建文件Views/Parts/Address.cshtml:

    View Code
    <p class="adr">
    <div class="street-address">@Model.Address</div>
    <span class="locality">@Model.City</span>,
    <span class="region">@Model.StateCode</span>
    <span class="postal-code">@Model.Zip</span>
    </p>

    • 编辑视图

    新建文件Views/ EditorTemplates/Parts/Address.cshtml:

    View Code
    @model RelationSample.ViewModels.EditAddressViewModel
    <fieldset>
    <legend>Address</legend>

    <div class="editor-label">
    @Html.LabelFor(model
    => model.Address, T("Street Address"))
    </div>
    <div class="editor-field">
    @Html.TextAreaFor(model
    => model.Address)
    @Html.ValidationMessageFor(model
    => model.Address)
    </div>

    <div class="editor-label">
    @Html.LabelFor(model
    => model.City, T("City"))
    </div>
    <div class="editor-field">
    @Html.TextBoxFor(model
    => model.City)
    @Html.ValidationMessageFor(model
    => model.City)
    </div>

    <div class="editor-label">
    @Html.LabelFor(model
    => model.StateCode, T("State"))
    </div>
    <div class="editor-field">
    @Html.DropDownListFor(model
    => model.StateCode,
    Model.States.Select(s
    => new SelectListItem {
    Selected
    = s.Code == Model.StateCode,
    Text
    = s.Code + " " + s.Name,
    Value
    = s.Code
    }),
    "Choose a state...")
    @Html.ValidationMessageFor(model
    => model.StateCode)
    </div>

    <div class="editor-label">
    @Html.LabelFor(model
    => model.Zip, T("Zip"))
    </div>
    <div class="editor-field">
    @Html.TextBoxFor(model
    => model.Zip)
    @Html.ValidationMessageFor(model
    => model.Zip)
    </div>
    </fieldset>

    The placement file

    项目根目录下新建part默认位置文件:

    View Code
    <Placement>
    <Place Parts_Address_Edit="Content:10"/>
    <Place Parts_Address="Content:10"/>
    </Placement>

    使用address part

    打开RelationSample功能之后,我们新建一个"Customer"内容类型:


    新建一个"Customer":

    前端显示为:


     

    推荐:你可能需要的在线电子书

     

    我的新浪围脖: http://t.sina.com.cn/openexpressapp

    欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

  • 相关阅读:
    LeetCode 623. Add One Row to Tree
    LeetCode 894. All Possible Full Binary Trees
    LeetCode 988. Smallest String Starting From Leaf
    LeetCode 979. Distribute Coins in Binary Tree
    LeetCode 814. Binary Tree Pruning
    LeetCode 951. Flip Equivalent Binary Trees
    LeetCode 426. Convert Binary Search Tree to Sorted Doubly Linked List
    LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal
    LeetCode 687. Longest Univalue Path
    LeetCode 428. Serialize and Deserialize N-ary Tree
  • 原文地址:https://www.cnblogs.com/zhoujg/p/1966742.html
Copyright © 2011-2022 走看看