OOM(对象与对象映射)场景设计和实现原理

在前文有一篇随笔,写了关于《UI与实体的映射》,有朋友建议写一下实现原理。今天我就整理一下,将OO映射的使用场景设计和实现原理描述一下。原来的实现比较拙劣,如果要发布成产品的话,还需要重构很多地方,以提高组件API的易用性和扩展性。注:该组件是2006年基于DOTNET 1.1实现的,因此没有泛型和其它现在比较时尚的功能。

1 OO映射使用场景设计

OO映射提出的目的是为了解决将UI对象转换成一个ORM中的实体,然后可以利用ORM直接将其持久化,避免一堆的幅值逻辑。先看一下映射类的定义,然后将定义不同的映射场景。所有的映射定义都是在实体类OO映射预定义的映射方式有Member与Member映射,Control与Member映射,Reference映射。同时,也支持自定义扩展。该组件只是一个个人用的,耗时4天完成,因此现有功能非常有限。
ContractedBlock.gif ExpandedBlockStart.gif Code
 1 /// <summary>
 2 /// 全局映射定义。
 3 /// </summary>
 4 [Map(DeployMode.SingleCall, "<Prefix>""<Postfix>")]
 5 public class UserEntity
 6 {
 7     /// <summary>
 8     /// 实现源对象与目标对象Age字段直接映射。
 9     /// </summary>
10     [Member]
11     public int Age;
12 
13     /// <summary>
14     /// 实现源对象与目标对象Set属性映射。
15     /// </summary>
16     [Member]
17     public bool Sex
18     {
19         set;
20         get;
21     }
22 
23     /// <summary>
24     /// 实现源UI对象的ID为Name的控件与Name的直接映射。
25     /// </summary>
26     [Control]
27     public string Name
28     {
29         set;
30         get;
31     }
32     /// <summary>
33     /// 实现源UI对象的ID为CardNo的控件的Text属性与CardNo直接映射。
34     /// </summary>
35     [Control("CardNo.Text")]
36     public string CardNo
37     {
38         set;
39         get;
40     }
41     /// <summary>
42     /// 引用映射。
43     /// </summary>
44     [Reference(typeof(EmployeeEntity))]
45     public EmployeeEntity Employee
46     {
47         get;
48         set;
49     }
50 }

1.1 Member映射场景

(1)UI对象与实体对象Public相同字段直接映射
[Member]
public int Age;
这个在实体类的映射定义指明了如下信息:1)UI类有一个Age字段;2)UI类的Age字段与实体类Age字段映射。
(2)UI对象字段的属性与实体直接映射
[Member("AgeObject.MyAge")]
public int Age;
该映射定义了实体类的Age将与UI类的AgeObject对象的MyAge字段/属性映射。属性可以串成一个路径方式,比如ObjectA.PropA1.PropA11.PropA111。
(3)UI对象与实体对象Public相同字段直接映射
[Member]
public bool Sex
{
set;
get;
}
定义实体类的Sex属性与UI的Sex字段/属性映射。
(4)UI对象字段的属性与实体直接映射
[Member("SexObject.MySex")]
public bool Sex
{
set;
get;
}
定义实体类Sex属性与UI类的SexObject类实例成员的Sex成员映射。

1.2 控件映射场景

UI类中控件与Member定义方式是一模一样的,只不过控件是一个比较特殊的Member。在OO映射组件里,每一个控件都有默认属性,在配置文件中定义。
以下是默认的定义。
ContractedBlock.gif ExpandedBlockStart.gif Code
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    
<configSections>
        
<section name="NullPathPairs" type="System.Configuration.NameValueSectionHandler, System, 
            Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"
 />
    
</configSections>
    
    
<NullPathPairs>
        
<!--WinControl-->
            
<!--Text-->
                
<add key="System.Windows.Forms.Button" value="Text" />
                
<add key="System.Windows.Forms.Label" value="Text" />
                
<add key="System.Windows.Forms.LinkLabel" value="Text" />
                
<add key="System.Windows.Forms.RichTextBox" value="Text" />
                
<add key="System.Windows.Forms.TextBox" value="Text" />
                
<add key="System.Windows.Forms.DataGridTextBox" value="Text" />
            
<!--Checked-->
                
<add key="System.Windows.Forms.CheckBox" value="Checked" />
                
<add key="System.Windows.Forms.RadioButton" value="Checked" />
            
<!--SelectedValue-->
                
<add key="System.Windows.Forms.ComboBox" value="SelectedValue" />
                
<add key="System.Windows.Forms.ListBox" value="SelectedValue" />
        
<!--WebControl-->
            
<!--Text-->
                
<add key="System.Web.UI.WebControls.TextBox" value="Text" />
                
<add key="System.Web.UI.WebControls.Label" value="Text" />
            
<!--Checked-->
                
<add key="System.Web.UI.WebControls.CheckBox" value="Checked" />
                
<add key="System.Web.UI.WebControls.RadioButton" value="Checked" />
            
<!--SelectedValue-->
                
<add key="System.Web.UI.WebControls.DropDownList" value="SelectedValue" />
                
<add key="System.Web.UI.WebControls.ListBox" value="SelectedValue" />
                
<add key="System.Web.UI.WebControls.RadioButtonList" value="SelectedValue" />
    
</NullPathPairs>
</configuration>

以下说明控件映射的场景。
(1)控件默认属性与成员映射
[Control]
public string Name
{
set;
get;
}
定义了UI类的Name控件的默认属性与实体类Name属性映射。如果Name控件是一个TextBox,那么其默认属性是Text。
(2)控件指定属性路径与成员映射
[Control("Name.Text")]
public string Name
{
set;
get;
}
实现UI类的Name控件的Text属性与实体类Name映射。

1.3 引用映射

引用映射定义一个实体类如果包含另一个实体类,他们都可以直接实现映射。
[Reference(typeof(EmployeeEntity))]
public EmployeeEntity Employee
{
get;
set;
}
该场景定义了实体类中的Employee也是一个支持OO映射的实体。当执行映射时,Employee成员也必须实现映射幅值。

1.4 全局映射定义

全局映射用于指定一个实体类的映射是否为单件模式、UI类与实体类成员命名前后缀差异。它的特性定义是应用于实体类,而不是成员。
/// <summary>
/// 全局映射定义。
/// </summary>
[Map(DeployMode.SingleCall, "<Prefix>", "<Postfix>")]
public class UserEntity

1.5 扩展场景

其它场景我原来没有实现,不过可以进行自定义扩展,比如方法与成员映射,动态更改映射属性等。

2 实现原理

OO映射组件的实现比较简单,核心类实现如下:


ObjectEngine是整个OO映射的入口,它定义了3个静态方法:SetMapper用于设置实现IObjectMapper的对象映射器,默认值为DefaultObjectMapper的实例。
IObjectMapper是实现OO映射的核心定义,它定义了默认的成员映射器和正向映射与反向映射方法。IObjectMapper在实现上将整个实体的映射分解成
每一个成员的映射,使用成员映射器实现每一个成员具体映射。DefaultMapper是IObjectMapper默认实现,它依赖与成员映射器工厂和实体类型描述缓存。
其实现如下:
ContractedBlock.gif ExpandedBlockStart.gif Code
 1 /// <summary>
 2 /// 对象映射器默认实现。
 3 /// </summary>
 4 public class DefaultObjectMapper:IObjectMapper
 5 {
 6     private IMemberMapper _defaultContextMapper;
 7     /// <summary>
 8     /// 默认成员映射器,当一个成员没有定义映射特性的时候,使用它执行映射。
 9     /// </summary>
10     public IMemberMapper DefaultMemberMapper
11     {
12         get
13         {
14             return _defaultContextMapper;
15         }
16         set
17         {
18             this._defaultContextMapper = value;
19         }
20     }
21     /// <summary>
22     /// 执行正向映射。
23     /// </summary>
24     /// <param name="source">源对象。</param>
25     /// <param name="target">目标对象。目标对象是一个实体类。</param>
26     public void Map(object source, object target)
27     {
28         Map(source, target, true);
29     }
30     /// <summary>
31     /// 执行反向映射。
32     /// </summary>
33     /// <param name="source">源对象。</param>
34     /// <param name="target">目标对象。目标对象是一个实体类。</param>
35     public void InverseMap(object source, object target)
36     {
37         Map(source, target, false);
38     }
39 
40     /// <summary>
41     /// 执行正向映射。
42     /// </summary>
43     /// <param name="source">源对象。</param>
44     /// <param name="target">目标对象。目标对象是一个实体类。</param>
45     public void Map(object source, object target, bool direct)
46     {
47         Type targetType = target.GetType();
48         // 获取目标对象的映射特性定义。
49         ObjectDescription targetDes = ObjectDesCache.Get(targetType);
50         // 遍历实体对象所有成员特性定义。
51         foreach (string member in targetDes.MemberAttributes.Keys)
52         {
53             // 获取当前成员的映射特性。
54             object[] memberAttributes = targetDes.MemberAttributes[member] as object[];
55             // 遍历所有映射特性。
56             foreach (object memberAttribute in memberAttributes)
57             {
58                 // 获取成员特性相对应的成员映射器,执行映射。
59                 IMemberMapper memberMapper = MemberMapperFactory.Get(
                        memberAttribute.GetType());
60                 if (memberMapper == null)
61                     continue;
62 
63                 if (direct) // 如果是正向,则执行正向映射。
64                 {
65                     memberMapper.Map(source, target, targetDes.MapContext, 
                              member, memberAttribute);
66                 }
67                 else //执行反向映射。
68                 {
69                     memberMapper.InverseMap(source, target, targetDes.MapContext, 
                              member, memberAttribute);
70                 }
71             }
72         }
73     }
74 }

IMemberMapper是实现实体成员映射的核心定义,它定义了与成员映射器对应的映射特性类型和正向映射与反向映射方法。目前有3个默认实现,分别是:MemberMapper、ControlMapper和ReferenceMapper,它们分别对应MemberAttribute、ControlAttribute和ReferenceAttribute特性。
MemberMapper的实现如下:
ContractedBlock.gif ExpandedBlockStart.gif Code
 1 /// <summary>
 2 /// 实现源对象成员与目标对象成员的映射。
 3 /// </summary>
 4 public class MemberMapper : MemberMapperBase
 5 {
 6     /// <summary>
 7     /// 执行成员正向映射。
 8     /// </summary>
 9     /// <param name="source">源对象。</param>
10     /// <param name="target">目标对象。</param>
11     /// <param name="globalMapAttribute">全局映射特性。</param>
12     /// <param name="member">成员名称。</param>
13     /// <param name="memberMapAttribute">成员映射特性。</param>
14     protected override void DoMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
15     {
16         MemberAttribute memAttr = memberMapAttribute as MemberAttribute;
17         // 获取声明的映射路径,如[Member("SexObject.MySex")]中的SetObject.MySet。
18         string path = memAttr.Path;
19         object[] parameters = memAttr.Params;
20         // 获取源对象指定路径的属性的值,然后设置到目标对象上,从而实现映射。
21         DynamicInvokeUtil.SetMember(target,member,DynamicInvokeUtil.GetMemberByPath(
                  source,path,parameters));
22     }
23     /// <summary>
24     /// 执行成员反向映射。
25     /// </summary>
26     /// <param name="source">源对象。</param>
27     /// <param name="target">目标对象。</param>
28     /// <param name="globalMapAttribute">全局映射特性。</param>
29     /// <param name="member">成员名称。</param>
30     /// <param name="memberMapAttribute">成员映射特性。</param>
31     protected override void DoInverseMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
32     {
33         MemberAttribute memAttr = memberMapAttribute as MemberAttribute;
34         string path = memAttr.Path;
35         object[] parameters = memAttr.Params;
36         // 获取目标对象成员的值。
37         object targetMemberValue = DynamicInvokeUtil.GetMember(target,member);
38         // 根据属性路径反向设置源对象成员的值。
39         DynamicInvokeUtil.SetMemberByPath(source,path,targetMemberValue,parameters);
40     }
41 }

ControlMapper的实现如下:
ContractedBlock.gif ExpandedBlockStart.gif Code
 1 /// <summary>
 2 /// 控件依赖格式声明为2种:
 3 /// 1.控件ID
 4 /// 2.控件ID.属性全路径
 5 /// </summary>
 6 public class ControlMapper : MemberMapperBase
 7 {
 8     /// <summary>
 9     /// 执行Control与实体类正向映射。
10     /// </summary>
11     /// <param name="source">源对象。</param>
12     /// <param name="target">目标对象。</param>
13     /// <param name="globalMapAttribute">全局映射特性。</param>
14     /// <param name="member">成员名称。</param>
15     /// <param name="memberMapAttribute">成员映射特性。</param>
16     protected override void DoMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
17     {
18         ControlAttribute memAttr = memberMapAttribute as ControlAttribute;
19         string path = memAttr.Path;
20         object[] parameters = memAttr.Params;
21         // 获取控件所在的WinForm或者WebForm代理类。
22         IFormBroker broker = FormBrokerFactory.Get(source.GetType());
23         AssertUtil.ArgumentNotNull(broker,"FormBroker");
24         
25         // 利用窗体代理类,使用路径获取控件属性路径对应的值。
26         object controlValue = broker.Get(source,path,memAttr.BrokerName,parameters);
27         // 将结果设置到目标实体类。
28         DynamicInvokeUtil.SetMember(target,member,controlValue);
29     }
30     /// <summary>
31     /// 执行控件与实体类的反向映射。
32     /// </summary>
33     /// <param name="source">源对象。</param>
34     /// <param name="target">目标对象。</param>
35     /// <param name="globalMapAttribute">全局映射特性。</param>
36     /// <param name="member">成员名称。</param>
37     /// <param name="memberMapAttribute">成员映射特性。</param>
38     protected override void DoInverseMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
39     {
40         ControlAttribute memAttr = memberMapAttribute as ControlAttribute;
41         string path = memAttr.Path;
42         object[] parameters = memAttr.Params;
43         // 获取控件所在的WinForm或者WebForm代理类。
44         IFormBroker broker = FormBrokerFactory.Get(source.GetType());
45         AssertUtil.ArgumentNotNull(broker,"broker");
46         // 获取实体成员的值。
47         object memberValue = DynamicInvokeUtil.GetMember(target,member);
48         // 利用窗体代理类将成员的值设置到控件上。
49         broker.Set(source,path,memberValue,memAttr.BrokerName,parameters);
50     }        
51 }

ReferenceMapper的实现如下:
ContractedBlock.gif ExpandedBlockStart.gif Code
 1 /// <summary>
 2 /// 执行引用映射。
 3 /// </summary>
 4 public class ReferenceMapper : MemberMapperBase
 5 {
 6 
 7     /// <summary>
 8     /// 执行正向映射。
 9     /// </summary>
10     /// <param name="source">源对象。</param>
11     /// <param name="target">目标对象。</param>
12     /// <param name="globalMapAttribute">全局映射特性。</param>
13     /// <param name="member">成员名称。</param>
14     /// <param name="memberMapAttribute">成员映射特性。</param>
15     protected override void DoMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
16     {
17         // 执行引用实体映射,获取其值。
18         object referenceObjectInstance = ObjectEngine.Map(source,
                  (memberMapAttribute 
as ReferenceAttribute).RefType);
19         // 设置对应的值。
20         DynamicInvokeUtil.SetMember(target,member,referenceObjectInstance);
21     }
22     /// <summary>
23     /// 执行反向映射。
24     /// </summary>
25     /// <param name="source">源对象。</param>
26     /// <param name="target">目标对象。</param>
27     /// <param name="globalMapAttribute">全局映射特性。</param>
28     /// <param name="member">成员名称。</param>
29     /// <param name="memberMapAttribute">成员映射特性。</param>
30     protected override void DoInverseMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
31     {
32         // 获取引用实体值。
33         object referenceObjectInstance = DynamicInvokeUtil.GetMember(target, member);
34         // 执行反向映射。
35         ObjectEngine.InverseMap(source, referenceObjectInstance);
36     }
37 }

 1 /// <summary>
 2 /// 执行引用映射。
 3 /// </summary>
 4 public class ReferenceMapper:IMemberMapper
 5 {
 6     private Type _memberAttributeType = typeof(ReferenceAttribute);
 7     /// <summary>
 8     /// 对性的成员特性类型。
 9     /// </summary>
10     public Type MemberAttributeType
11     {
12         get
13         {
14             return _memberAttributeType;
15         }
16     }
17 
18     /// <summary>
19     /// 执行正向映射。
20     /// </summary>
21     /// <param name="source">源对象。</param>
22     /// <param name="target">目标对象。</param>
23     /// <param name="globalMapAttribute">全局映射特性。</param>
24     /// <param name="member">成员名称。</param>
25     /// <param name="memberMapAttribute">成员映射特性。</param>
26     public void Map(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
27     {
28         // 执行引用实体映射,获取其值。
29         object referenceObjectInstance = ObjectEngine.Map(source,
                  (memberMapAttribute 
as ReferenceAttribute).RefType);
30         // 设置对应的值。
31         DynamicInvokeUtil.SetMember(target,member,referenceObjectInstance);
32     }
33     /// <summary>
34     /// 执行反向映射。
35     /// </summary>
36     /// <param name="source">源对象。</param>
37     /// <param name="target">目标对象。</param>
38     /// <param name="globalMapAttribute">全局映射特性。</param>
39     /// <param name="member">成员名称。</param>
40     /// <param name="memberMapAttribute">成员映射特性。</param>
41     public void InverseMap(object source, object target, 
            
object globalMapAttribute, string member, object memberMapAttribute)
42     {
43         // 获取引用实体值。
44         object referenceObjectInstance = DynamicInvokeUtil.GetMember(target, member);
45         // 执行反向映射。
46         ObjectEngine.InverseMap(source, referenceObjectInstance);
47     }
48 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值