一年以来我最好的创意

从Kanas.Net 1.0开始,我对元数据的处理都是这样的:
TypeBroker:收集与实体类型相关的元数据信息,包括反射信息和映射信息;
PropertyBroker:收集与实体类型的属性相关的元数据信息,包括反射信息和映射信息。
这应该是必须经历的一步,是整个环境上下文信息中最重要的一部分。

在业务层很难避免对实体元数据信息的操作,例如定位实体类或者定位实体属性。
实体类型的问题还比较好办,毕竟在C#下可以使用typeof运算符。实体属性就比较麻烦了。

 

以往采用三种方式:

  • 实体类型+属性序号,如:(typeof(Cat), 2)
  • 实体类型+属性名称,如:(typeof(Cat), "Name")
  • 属性全名称,如:("Cat.Name")

 

显然,以上三种方式都不够优雅。
看看Hibernate如何处理:

List cats = sess.createCriteria(Cat.class)
.add( Expression.like("name", "Fritz%") )

从Cat实体中检索名称含Fritz的实例集合,和我的方法二一样。
注意到那个"name",不仅需要开发者记住对Cat的name属性的命名,而且还逃过了设计期的类型检查,所有的错误必须到运行期才知道。

现在我在实体信息之外加了一个元数据词典,解决了这个问题。因为所有的实体类型的源代码都是工具生成的,所以再顺便生成一个元数据词典代价低廉。

具体实现是这样的:
 

定义实现一个抽象类:Entity

为每个实体类都建立一个词典类,继承自Entity或者Entity的派生类,每个类都指向相应的实体类型。例如名称为Entity_User的类型指向User实体。

在每个嵌套类型中为对应的实体类的每个属性定义一个对应的属性,该属性的名称为对应实体属性的名称,其值为对应属性的元数据。

Entity类中为每个嵌套类定义一个私有的静态实例,并通过只读的静态属性暴露该静态实例。
这是示例代码:

public abstract class Entity
{
    intern Entity(Type entityType)
    
{
        
if (entityType != null
)
        
{
            
if (typeof
(BizObject).IsAssignableFrom(entityType))
            
{
                _Type 
=
 TypeBroker.Types[entityType];
            }

            
else
            
{
                
throw new ArgumentException("指定的类型不是实体类型""entityType"
);
            }

        }

        
else
        
{
            
throw new ArgumentException("尚未指定实体类型""entityType"
);
        }

    }


    
protected TypeBroker _Type;

    
protected PropertyBroker PropertyOf(int
 propertyindex)
    
{
        PropertyBrokerCollection properties 
=
 _Type.Properties;
        
if (properties.Count > propertyIndex && 0 <=
 propertyIndex)
        
{
            
return
 properties[propertyIndex];
        }

        
else
        
{
            
throw new ArgumentException("指定的属性序号无效""propertyIndex"
);
        }

    }


    
private static Entity_Pet _Pet = new Entity_Pet();
    
    
public static
 Entity_Pet Pet
    
{
        
get

        
{
            
return
 _Pet;
        }

    }


    
private static Entity_Cat _Cat = new Entity_Cat();
    
    
public static
 Entity_Cat Cat
    
{
        
get

        
{
            
return
 _Cat;
        }

    }


    
public static implicit operator TypeBroker(Entity entity)
    
{
        
return
 entity._Type;
    }

}


public class Entity_Pet : Entity
{
    intern Entity_Pet() : 
base(typeof
(Pet))
    
{
    }


    intern Entity_Cat(Type entityType) : 
base(entityType)
    
{
    }


    
public PropertyBroker ID
    
{
        
get

        
{
            
return PropertyOf(typeof(Cat), 0
);
        }

    }


    
public PropertyBroker Name
    
{
        
get

        
{
            
return PropertyOf(typeof(Cat), 1
);
        }

    }

}


public class Entity_Cat : Entity_Pet
{
    intern Entity_Cat() : 
base(typeof
(Cat))
    
{
    }


    
public PropertyBroker Color
    
{
        
get

        
{
            
return PropertyOf(typeof(Cat), 2
);
        }

    }

}
以上示例代码包含以下语义:
Entity.Pet表示宠物实体;Entity.Cat表示猫实体;
Entity.Pet.ID表示宠物的标识属性,Entity.Pet.Name表示宠物的名称属性;
Entity.Cat.ID表示猫的标识属性,Entity.Cat.Name表示猫的名称属性,Entity.Cat.Color表示猫的颜色属性。

于是,以上Hibernate实现检索的代码在我这里变成这样了:
StringConstraint.By(Entity.Cat.Name).Like("Frantz@")
在IDE环境下,敲入“Entity.”后会弹出所有实体类型名称;敲入“Entity.Cat.”后会弹出Cat这个实体类型所有的属性。如果你愿意在Entity的Cat静态属性上加上summary注释,还会提示实体类型的概念名呢!
posted @ 2005-07-26 16:28  双鱼座  阅读(2855)  评论(34)    收藏  举报