博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Orchard:处理1对多的关系
阅读量:6256 次
发布时间:2019-06-22

本文共 8610 字,大约阅读时间需要 28 分钟。

建立个人通讯内容时,从一个城市列表中下拉选择所在城市是非常普通的一个应用,这就是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":

前端显示为:

 

 本文转自 陈本峰 51CTO博客,原文链接:http://blog.51cto.com/zhoujg/516633,如需转载请自行联系原作者

你可能感兴趣的文章
uni-app采坑记录
查看>>
TP方法中打印地址栏中所有的参数:
查看>>
这是一个蒟蒻的计划……QAQ
查看>>
设置局域网共享文件不需要用户名密码
查看>>
raft--分布式一致性协议
查看>>
Solidity notes
查看>>
网上购物系统(Task005)——通用数据库访问函数集SqlHelper类
查看>>
java 单例模式浅析
查看>>
Codeforces Round #389 (Div. 2,) B C
查看>>
python中configparser模块记录
查看>>
IIIDX[九省联考2018]
查看>>
Protobuf3 序列化
查看>>
C语言面试题大汇总
查看>>
JavaSE-List常用方法
查看>>
json 和 pickel 详解
查看>>
Linux基础命令之grep
查看>>
python自动化开发-7
查看>>
使用VS2010+SVN出現的問題
查看>>
谁说Javascript简单的?
查看>>
UVA 1374 Power Calculus
查看>>