一点一滴之NHibernate

时间:2023-12-31 14:57:09

之前介绍了Dapper,速度很快,很轻量,很好用。

但是Dapper其实有自己的弊端,比如在数据关系复杂,数据库表非常多,多数据库支持,数据库结构变动频繁的时候总是很无奈。尽管有代码生成器,但是代码生成器本来就有自身的许多劣根性,比如生成的代码单一,虽然可以用,但是也仅限制在CURD上。把数据库改下了,之前辛苦修改的代码又要重新再改一次,当然这个有方法解决,但是总是带来许多新的问题。

这个也几乎是所有轻量级ORM都会面临的一个问题。

后来实在被这个问题快搞崩溃了,于是写个小工具,希望设计好模型之后,直接生成不同的数据库结构,生成不同的代码表单页面,结果人懒到最后没写完还停在那里,可见这里

再后来就用上了NHibernate。

NHibernate是一个很强的ORM.尽管让人诟病它的配置项,它的速度,但是亮点也总是很多,甚至超过了java版本。

OK 先来入门。定义几个基础的对象

public class CompanyGroup
    {
        public CompanyGroup() : this(string.Empty) { }

        public CompanyGroup(string name)
        {
            this.CompanyGroupName = name;
        }

        public virtual long CompanyGroupId { get; set; }

        public virtual string CompanyGroupName { get; set; }

        public virtual Company Company { get; set; }

        public virtual DateTime CreateTime { get; set; }

        public virtual CompanyGroupExtend CompanyGroupExtend
        {
            get;
            set;
        }
    }
    /// <summary>
    /// 公司组扩展信息
    /// </summary>
    public class CompanyGroupExtend
    {
        /// <summary>
        /// 扩展信息编号
        /// </summary>
        public virtual long ExtendId { get; set; }

        /// <summary>
        /// 公司组别名
        /// </summary>
        public virtual string CompanyGroupAliases { get; set; }

        /// <summary>
        /// 对应公司组
        /// </summary>
        public virtual CompanyGroup CompanyGroup { get; set; }
    }
public class Company
    {
        public Company()
            : this(null)
        {

        }

        public Company(string name)
        {
            this.CompanyName = name;
            this.CompanyGroups = new List<CompanyGroup>(8);
        }

        public virtual long CompanyId { get; set; }

        public virtual string CompanyName { get; set; }

        public virtual string CompanyDescription { get; set; }

        public virtual DateTime CreateTime { get; set; }

        public virtual ICollection<CompanyGroup> CompanyGroups { get; set; }

        public virtual void AddCompanyGroup(CompanyGroup group)
        {
            if (!this.CompanyGroups.Contains(group))
            {
                this.CompanyGroups.Add(group);

            }
            return;
        }

        public virtual void RemoveCompanyGroup(CompanyGroup group)
        {
            if (this.CompanyGroups.Contains(group))
            {
                this.CompanyGroups.Remove(group);
            }
            return;
        }

    }

几个基础的实体类也反应了一组基础的关于,分别是1:m,和1:1两种管理。

一点一滴之NHibernate

NHibernate3.x之前,需要配置坑爹的xml,这个是个吐槽点,尽管装了xsd能够智能的感知以及修改,但是都忍不住吐槽,看了被c#惯坏了。

在NHibernate3.x以后可以直接进行手动的代码配置。比如

    public class CompanyGroupExtendMap : ClassMapping<CompanyGroupExtend>
    {
        public CompanyGroupExtendMap()
        {
            base.Id(c => c.ExtendId, map =>
            {
                map.Generator(Generators.Foreign<CompanyGroup>(c => c.CompanyGroupExtend));
            });

            base.Property(c => c.CompanyGroupAliases, map =>
            {
                map.Length(50);
                map.NotNullable(true);
            });

            base.OneToOne(c => c.CompanyGroup, map =>
            {
                map.Constrained(true);
                map.Cascade(Cascade.All);
            });
        }
    }
public class CompanyGroupMap : ClassMapping<CompanyGroup>
    {
        public CompanyGroupMap()
        {
            base.Id(c => c.CompanyGroupId, map => { map.Generator(Generators.Native); });
            base.Property(c => c.CompanyGroupName, map => { map.Length(50); map.NotNullable(true); });
            base.Property(c => c.CreateTime, map => map.NotNullable(true));
            base.ManyToOne<Company>(c => c.Company, map =>
            {
                map.Column("CompanyId");
                map.Cascade(Cascade.None);
            });
            base.OneToOne(c => c.CompanyGroupExtend, map =>
            {
                map.Cascade(Cascade.All);
                map.Lazy(LazyRelation.Proxy);
            });
        }
    }
    public class CompanyMap : ClassMapping<Company>
    {
        public CompanyMap()
        {
            base.Id(c => c.CompanyId, map =>
            {
                map.Generator(Generators.Native);
                map.Column("CompanyId");
            });
            base.Property(c => c.CompanyName, map =>
            {
                map.Length(50);
                map.NotNullable(true);
            });

            base.Property(c => c.CreateTime, map =>
            {
                map.NotNullable(true);
            });

            base.Property(c => c.CompanyDescription, map =>
            {
                map.Length(SqlClientDriver.MaxSizeForLengthLimitedString + 1);
            });

            base.Set(c => c.CompanyGroups, map =>
            {
                map.Key(r => { r.Column("CompanyId"); });
                map.Cascade(Cascade.All);
                map.Inverse(false);
            }, action => action.OneToMany());
        }
    }

于是通过派生ModelMapper即可实现数据库的生成策略,以及生成数据库对象。

public class DatabaseGenerationStrategyMapper : ModelMapper
    {
        public DatabaseGenerationStrategyMapper()
        {
            //base.BeforeMapClass += (mi, propertyPath, map) => map.Table((propertyPath.Name + "Info").ToLower());
            //base.BeforeMapProperty += (mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToLower());
            base.AfterMapManyToOne += (mi, propertyPath, map) =>
            {
                map.Column((propertyPath.LocalMember.Name + "Id"));
                map.ForeignKey(string.Format("FK_{0}_{1}_{2}", propertyPath.LocalMember.Name, propertyPath.LocalMember.DeclaringType.Name, Guid.NewGuid().ToString().Substring(0, 8).ToUpper()));
            };
            base.AfterMapOneToOne += (mi, propertyPath, map) =>
            {
                map.ForeignKey(string.Format("FK_{0}_{1}_{2}", propertyPath.LocalMember.Name, propertyPath.LocalMember.DeclaringType.Name, Guid.NewGuid().ToString().Substring(0, 8).ToUpper()));
            };
        }
    }
public class DatabaseMapper : DatabaseGenerationStrategyMapper
    {
        public DatabaseMapper()
        {
            base.AddMapping<CompanyGroupExtendMap>();
            base.AddMapping<CompanyGroupMap>();
            base.AddMapping<CompanyMap>();
            base.AddMapping<UserMap>();
        }

        public override string ToString()
        {
            return this.CompileMappingForAllExplicitlyAddedEntities().AsString();
        }
    }

OK 配置搞定。

直接测试下看看。

var configure = new Configuration();
            configure.SessionFactoryName("Demo");
            configure.DataBaseIntegration(db =>
            {
                db.Dialect<MsSql2005Dialect>();
                db.Driver<SqlClientDriver>();
                db.ConnectionString = @"Data Source=*;Initial Catalog=Database;User ID=sa;Password=123456;";
                db.LogSqlInConsole = true;
            });
            configure.AddMapping(new DatabaseMapper().CompileMappingForAllExplicitlyAddedEntities());

            SchemaMetadataUpdater.QuoteTableAndColumns(configure);
            new SchemaExport(configure).Create(false, true);

            using (ISession session = configure.BuildSessionFactory().OpenSession())
            {
                var company = new Company()
                {
                    CompanyName = "TestCompany",
                    CompanyDescription = "Description",
                    CreateTime = DateTime.Now
                };

                for (int i = 0; i < 100; i++)
                {
                    var group = new CompanyGroup(Guid.NewGuid().ToString());
                    group.CreateTime = DateTime.Now;
                    group.CompanyGroupName = "Test" + i.ToString();
                    company.AddCompanyGroup(group);
                }

                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Save(company);
                    transaction.Commit();
                }
            }

            using (ISession session = configure.BuildSessionFactory().OpenSession())
            {
                var info = session.Get<Company>(1L);
            }

            using (ISession session = configure.BuildSessionFactory().OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    var info = session.Get<Company>(1L);
                    session.Delete(info);
                    transaction.Commit();
                }
            }

            using (ISession session = configure.BuildSessionFactory().OpenSession())
            {
                var pagesize = 10;
                var current = 1;

                var count = session.QueryOver<CompanyGroup>().Where(r => r.Company.CompanyId == 1).RowCount();
                var infos = session.QueryOver<CompanyGroup>().Where(r => r.Company.CompanyId == 1).Skip(current * pagesize - pagesize).Take(pagesize).List();
                Console.WriteLine(count);
            }

很简单实现了增删改查,级联操作,和多关系操作。

感谢李永京的NHibernate讲解,俺也是看着他的博客入门的,在他的博客里讲解的很详细,有兴趣的可以去看下。