zoukankan      html  css  js  c++  java
  • LLBL Gen Pro 设计器使用指南

    LLBL Gen Pro是个专业的ORM开发工具,官方网站是 http://www.llblgen.com/

    LLBL Gen Pro是个支持多种持久层框架的ORM工具,如LLBL Gen Pro Runtime、Entity Framework、NHibernate和LINQ to SQL。其他一些新特性还有:

    支持.NET 4.0、模型先行或数据库先行的开发模式、模型视图、项目验证。LLBL Gen Pro有两个主要的组件:一是设计器,

    这是一个可视化工具,供开发者创建项目所用;二是运行时,这是与数据库交互的持久层框架,用于执行映射操作。

    1 设计实体类型

    打开LLBL Gen程序,选择创建新项目

    clip_image002

    打开Catelog Explorer,选择从数据库添加关系对象模型

    clip_image004

    输入SQL Server实例名称,登陆用户和秘密,点”Test Connection”测试连接

    clip_image006

    测试连接成功后,点击Next按钮,进行到下一步,选择数据库表

    clip_image008

    如果需要支持存储过程调用,可选择勾选存储过程

    clip_image010

    LLBL Gen开始读取系统表信息,供生成实体定义。

    在Catelog Explorer点选右键,选择从表定义中生成实体

    clip_image012

    如果表名带有简写,可以输入一个有意义容易理解的实体名称

    clip_image014

    LLBL Gen不建议的命名方法

    1. 在表名前加前缀。比如给客户表名定义成tblCustomer, 用户表定义成tblUser,只要是表都加一个tbl标签。如果是手写SQL语句,这可以区分出表和自定义的实体,但是ORM会对每个生成的实体名称后面加Entity,比如Employee表,默认会对生EmployeeEntity。

    为此,LLBL Gen设计了名称剔除(strip)模式,请看下图中的配置属性

    clip_image016

    2. 同样的原理,存储过程也不应该加sp_前缀,视图也不应该加vw_。

    2 修改实体属性

    在Project Exploer窗口中,选择要修改的实体名,点击编辑

    clip_image018

    默认情况下,不需要做修改,LLBL Gen会生成合适的数据库与实体映射。但是有以下几种情况需要修改。

    2.1 空值类型

    数据库字段值允许为空,对应生成的代码类型应该是NULLABLE,通常看到的可空类型。

    生成的代码例子

    /// <summary> The CreatedDate property of the Entity User<br/><br/>
    
    ///Mapped on table field: User.CreatedDate</summary>
    
    /// <remarks>Mapped on table field: "User"."CreatedDate"<br/>
    
    /// Table field type characteristics (type, precision, scale, length): DateTime, 0, 0, 0<br/>
    
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
    
    public virtual Nullable<System.DateTime> CreatedDate
    
    {
    
    get { return (Nullable<System.DateTime>)GetValue((int)UserFieldIndex.CreatedDate, false); }
    
    set { SetValue((int)UserFieldIndex.CreatedDate, value); }
    
    }

    如果不想生成这种类型,可在Field mapping窗口中,选择对应的属性名称,去掉Is nullable标签。

    clip_image020

    再次生成代码,它生成的属性应该是这样的

    /// <summary> The CreatedDate property of the Entity User<br/><br/>
    
    ///Mapped on table field: User.CreatedDate</summary>
    
    /// <remarks>Mapped on table field: "User"."CreatedDate"<br/>
    
    /// Table field type characteristics (type, precision, scale, length): DateTime, 0, 0, 0<br/>
    
    /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
    
    public virtual System.DateTime CreatedDate
    
    {
    
    get { return (Nullable<System.DateTime>)GetValue((int)UserFieldIndex.CreatedDate, false); }
    
    set { SetValue((int)UserFieldIndex.CreatedDate, value); }
    
    }

    2.2 自定义属性

    LLBL Gen支持为实体增加自定义属性,独立于数据库字段映射之外的属性,相当于代码生成器。

    clip_image022

    在生成代码中,会产生额外的属性,它的类型是Dictionary

    private static void SetupCustomPropertyHashtables()
    
    {
    
    _customProperties = new Dictionary<string, string>();
    
    _fieldsCustomProperties = new Dictionary<string, Dictionary<string, string>>();
    
    Dictionary<string, string> fieldHashtable;
    
    _fieldsCustomProperties.Add("UserName", fieldHashtable);
    
    fieldHashtable = new Dictionary<string, string>();
    
    fieldHashtable.Add("AllowEditForNewOnly", @"");
    
    }

    在运行时,可通过下面的方法,找到自定义属性

    // [C#]
    
    Dictionary<string, string> userProperties = UserEntity.CustomProperties;
    
    string description = userProperties ["AllowEditForNewOnly "];

    2.3 类型转化器

    如果需要对值进行类型转化。比如数据库中存储的是字符串,但要在程序中以bool类型来使用,可设置TypeConverter to use

    clip_image024

    强类型编程的好处是可以发现编译时错误,而不是到运行才出现错误。

    举例说明,我们常用1或0表示销售单已经过帐或没有过帐,但是在程序中以1或0来设置,缺少编译期间的检查,即使你赋值时给它值3,也不会有编译错误。如果换成bool类型,true表是已经过帐,false表示没有过帐,则可以极大的增加可维护性。

    请参考如下的代码,了解类型转换器,进一步的原理请参考.NET组件设计。

    Namespace TypeConverters
    {
        [Description("Converter with as core type System.Boolean, for mapping a field with a .NET type System.Boolean onto a string database field")]
        public class BooleanStringConverter : TypeConverter
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="BooleanStringConverter"/> class.
            /// </summary>
            public BooleanStringConverter()
            {
            }
    
            /// <summary>
            /// Returns whether this converter can convert an object of the given type to the type of this converter (Boolean).
            /// </summary>
            /// <param name="context">Ignored</param>
            /// <param name="sourceType">A <see cref="T:System.Type"/> that represents the type you want to convert from.</param>
            /// <returns>
            ///  <see langword="true "/>if this converter can perform the conversion; otherwise, <see langword="false"/>.
            /// </returns>
            /// <remarks>Accepted types are: String</remarks>
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                // any integer type is accepted. No fractional types like float/double.
                switch (sourceType.FullName)
                {
                    case "System.String":
                        return true;
                    default:
                        return false;
                }
            }
    
            /// <summary>
            /// Returns whether this converter can convert the object to the specified type.
            /// </summary>
            /// <param name="context">Ignored</param>
            /// <param name="destinationType">A <see cref="T:System.Type"/> that represents the type you want to convert to.</param>
            /// <returns>
            ///  <see langword="true "/>if this converter can perform the conversion; otherwise, <see langword="false"/>.
            /// </returns>
            /// <remarks>Accepted types are: String. True will be converted to 1, false will be
            /// converted to 0.</remarks>
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                // any integer type is accepted. No fractional types like float/double.
                switch (destinationType.FullName)
                {
                    case "System.String":
                        return true;
                    default:
                        return false;
                }
            }
    
            /// <summary>
            /// Converts the given object to the type of this converter (Boolean).
            /// </summary>
            /// <param name="context">Ignored</param>
            /// <param name="culture">Ignored</param>
            /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
            /// <returns>
            /// An <see cref="T:System.Object"/> that represents the converted value, which is of type boolean.
            /// </returns>
            /// <exception cref="T:System.NotSupportedException">The conversion could not be performed.</exception>
            public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
            {
                bool toReturn = true;
                switch (value.GetType().FullName)
                {
                    case "System.String":
                        toReturn = ((string)value == "Y");
                        break;
                    case "System.DBNull":
                        toReturn = false;
                        break;
                    default:
                        throw new NotSupportedException("Conversion from a value of type '" + value.GetType().ToString() + "' to System.Boolean isn't supported");
                }
    
                return toReturn;
            }
    
            /// <summary>
            /// Converts the given value object to the specified type
            /// </summary>
            /// <param name="context">Ignored</param>
            /// <param name="culture">Ignored</param>
            /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
            /// <param name="destinationType">The <see cref="T:System.Type"/> to convert the <paramref name="value"/> parameter to.</param>
            /// <returns>
            /// An <see cref="T:System.Object"/> that represents the converted value. The value will be 1 if <paramref name="value"/> is true, otherwise 0
            /// </returns>
            /// <exception cref="T:System.ArgumentNullException">The <paramref name="destinationType"/> parameter is <see langword="null"/>.</exception>
            /// <exception cref="T:System.NotSupportedException">The conversion could not be performed.</exception>
            public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value", "Value can't be null");
                }
    
                if (!(value is bool))
                {
                    throw new ArgumentException("Value isn't of type boolean", "value");
                }
    
                if ((bool)value)
                {
                    switch (destinationType.FullName)
                    {
                        case "System.String":
                            return (string)"Y";
                        case "System.DBNull":
                            return (string)"N";
    
                        default:
                            throw new NotSupportedException("Conversion to a value of type '" + destinationType.ToString() + "' isn't supported");
                    }
                }
                else
                {
                    switch (destinationType.FullName)
                    {
                        case "System.String":
                        case "System.DBNull":
                            return (string)"N";
                        default:
                            throw new NotSupportedException("Conversion to a value of type '" + destinationType.ToString() + "' isn't supported");
                    }
                }
            }
    
            /// <summary>
            /// Creates an instance of the Type that this <see cref="T:System.ComponentModel.TypeConverter"/> is associated with (bool)
            /// </summary>
            /// <param name="context">ignored.</param>
            /// <param name="propertyValues">ignored.</param>
            /// <returns>
            /// An <see cref="T:System.Object"/> of type bool. It always returns 'true' for this converter.
            /// </returns>
            public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
            {
                return true;
            }
        }
    }

    3 生成源代码

    设置好属性后,可用生成源代码,F7调出生成窗口

    clip_image026

    Template group中Adapter 模式把数据和数据的读写独立成二个部分,SelfServicing则混合两者

    Adapter模式下,读取用户的代码,如下所示

    UserLogEntity _UserLog = new UserLogEntity(Logno);
    
    using (DataAccessAdapterBase adapter = GetSystemDataAccessAdapter())
    
    {
    
    bool found = adapter.FetchEntity(_UserLog, prefetchPath, null, fieldList);
    
    if (!found) throw new RecordNotFoundException("Invalid UserLog");
    
    }

    SelfServicing模式,则是这样的

    CustomerEntity customer = new CustomerEntity();
    
    customer.FetchUsingPK("CHOPS");

    实际过程中,生成器生成的代码和自己加入的业务逻辑分开存放,当数据库更新字段时,再次生成代码,为了不覆盖已经加入的代码,常常要把自己的逻辑放到代码生成器生成的代码之外。

    clip_image028

    在我的项目中,我是将Database Generic和Database Specific两个项目的代码放在一起,在同一个项目中进行编译。

    clip_image030

    框架中大量依赖于这个设置,对生成的实体代码进行反射,读取元数据。

    4 MySQL 快速开发

    4.1 MySQL 安装配置

    安装MySQL, 使用查询分析器连接数据库服务器

    clip_image032

    创建数据库CTU, 并且创建新表Agent

    clip_image034

    给数据表Agent添加三笔数据,Jack,Tony,Charles

    clip_image036

    数据库设计的任务到此为止,记得给每个表添加主键。这里设置的主键是Name

    4.2 LLBL Gen 设计实体模型

    启动LLBL Gen 3.1, 创建新的项目,注意选择Target为LLBL Gen框架

    clip_image038

    在Category Explorer窗口中,右键,添加新连接

    clip_image040

    请在context菜单中选择Reverse-engineer Tables to Entity Definitions

    clip_image042

    这些表就会自动mapping到实体集合中

    clip_image044

    从图中可以看到,已经发现了Agent表

    如果需要进一步的编辑属性与字段的映射关系,请用Edit 菜单,打开窗体

    clip_image046

    在这里,可以设置关系,设置映射的名称。

    F7,可以开始生成代码

    clip_image048

    默认情况下,会生成2个项目文件

    clip_image050

    从名称中可以看出,一个是数据库无关的,另一个是做数据访问的。以此的原理是我们在生成数据库时,选择Adapter模式,而不是SelfServicing模式.

    4.3 启动程序

    在Visual Studio中打开生成的代码,并且添加测试项目(Console)

    解决方案浏览器中现在有三个项目Main是我们用来测试数据访问的

    clip_image052

    再来看一下Main方法,只有简单的几行程序,也就是一个最简单的测试程序

    UserEntity user=new UserEntity("Jack")
    DataAccessAdapter adapter=new DataAccessAdapter();
    adapter.FetchEntity(user);
    string title=user.Description;

    它会生成SQL语句 SELECT Name , Postion , Description FROM agent

    LLBL Gen支持NHibernate,ADO.NET Entity Framework,可以考虑用它来作为ORM框架,实现三层架构中的数据访问层。

  • 相关阅读:
    slice()、substring()、substr()的区别用法
    程序员如何快速上手一个自己不太熟悉的新项目?有什么技巧?
    计算重复字符串长度
    计算机视觉算法研发岗招聘要求
    C++进阶STL-2
    C++进阶STL-1
    拼硬币
    序列找数
    寻找合法字符串
    字符串是否由子串拼接
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/3079230.html
Copyright © 2011-2022 走看看