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的代码

    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

    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一样:

    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列表。

    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

    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:

    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:

    <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:

    @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默认位置文件:

    <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/ ]

  • 相关阅读:
    ACTIVE OBJECT 模式
    Node.js
    WordPress — 突破性能瓶颈,使用 WordPress 站群做 SEO 推广
    HttpRequest.Item 属性 和 HttpRequest.QueryString 属性的区别!
    Regex.Replace 方法的性能!(090625最新修改)
    FACTORY 模式
    Indexof String By Byte[]
    [11]DIP:依赖倒置原则
    C#.Net Winform skin 皮肤 大全(转)
    C# 情缘
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1966794.html
Copyright © 2011-2022 走看看