新做的NHibernate项目,大家来拍拍砖,同时还要请多多提些问题

简单说明:

这个项目的结构,大家来拍拍砖,同时还要请多多提些问题。

项目不是为了做新闻,由于对新闻比较了解,不同的项目中也用的多,我就想通过这个项目吧新闻功能做的深入完善些,这里也就用新闻做演示用。

这个结构是根据之前的项目结构,以及院子里不是朋友们的提供的方案、代码等,整合起来的。不敢妄称为啥框架,只是希望对开发的项目能起到一些帮助作用。

第一次写blog,可能有点乱,大家见谅了。


使用结构资源

NHibernate.net
FluentNHibernate
Autofac
MVC
Jquery

项目结构

总体结构

说明下为啥这样做: 我工作的单位都是变化比较快的公司(命苦呀),很多事情都是比较杂,之前的项目就是模块太多了,维护起来很麻烦,我就想可不可以按照功能模块来划分, 吧一个模块深入,又不影响其他人的工作。。。 所以倒腾了这样的一个结果。(受到SpaceBuilder影响).

另外一个想法是:今后项目扩展性会好些; 模块的延续行也会提升。像之前在不同的公司,项目中的新闻还要拿出来改啊啥的。 如果这个结果吧新闻模块完善后,其他项目只需要引用改模块即可。



文章咨询模块


稍微了解过NHibernate.net应该能开出来大概的结构意思吧? 还是上几段代码吧。

using System;
using System.Linq;
using System.Text;

using Job.FluenCore.Common;
using Iesi.Collections.Generic;

namespace Job.FluenCore.Article.Model
{
    public class News : IEntity
    {
        /// <summary>
        /// 文章编号
        /// </summary>
        public virtual int Id { get; set; }

        /// <summary>
        /// 新闻类型何种类型
        /// 文章、单页
        /// News.TypeId =NewsClass.TypeId
        /// </summary>
        public virtual NewsClassType TypeId { get; set; }

        /// <summary>
        /// News.ClassId =NewsClass.ClassId
        /// </summary>
        public virtual int ClassId { get; set; }

        /// <summary>
        /// 访问次数
        /// </summary>
        public virtual int Visits { get; set; }
        /// <summary>
        /// 添加时间
        /// </summary>
        public virtual DateTime AddTime { get; set; }
        /// <summary>
        /// 编辑时间
        /// </summary>
        public virtual DateTime EditTime { get; set; }
        /// <summary>
        /// 文章状态
        /// </summary>
        public virtual NewAuditType ContentStatus { get; set; }


        /// <summary>
        /// 主题 详细页
        /// </summary>
        public virtual string Title { get; set; }
        /// <summary>
        /// 主题颜色
        /// </summary>
        public virtual string TitleColor { get; set; }
        /// <summary>
        /// 复标题 用于首页等。
        /// </summary>
        public virtual string TitleSub { get; set; }
        /// <summary>
        /// 内容
        /// </summary>
        public virtual string Content { get; set; }
        /// <summary>
        /// 作者
        /// </summary>
        public virtual string Author { get; set; }
        /// <summary>
        /// 简介
        /// </summary>
        public virtual string Introduction { get; set; }

        /// <summary>
        /// seo
        /// </summary>
        public virtual string PageTitle { get; set; }
        /// <summary>
        /// seo
        /// </summary>
        public virtual string PageKeywords { get; set; }
        /// <summary>
        /// seo
        /// </summary>
        public virtual string PageDescription { get; set; }

        /// <summary>
        /// 置顶
        /// </summary>
        public virtual byte IsTop { get; set; }
        /// <summary>
        /// 推荐
        /// </summary>
        public virtual byte IsRecommend { get; set; }
        /// <summary>
        /// 回复
        /// </summary>
        public virtual byte IsNoComment { get; set; }
        /// <summary>
        /// 文章星级 默认 0
        /// </summary>
        public virtual short Star { get; set; }
        /// <summary>
        /// 文章排序 默认 0
        /// </summary>
        public virtual int ContentOrder { get; set; }
        /// <summary>
        /// 文章Url
        /// </summary>
        public virtual string ContentUrl { get; set; }

        /// <summary>
        /// 缩略图 编号
        /// </summary>
        public virtual int IndexImage { get; set; }
        
        /*
        /// <summary>
        /// 文章分类\
        /// 数据库字段=ClassID
        /// </summary>
        public virtual NewsClass Class { get; set; }
        /// <summary>
        /// 文章评论
        /// </summary>
        public virtual ISet<NewsComments> Comments { get; set; } 
        ///// <summary>
        ///// 图片 下载文件
        ///// </summary>
        public virtual ISet<NewsFile> Files { get; set; }
        */
    }
}
模型
using System;
//using System.Collections.Generic;
using System.Linq;

using Iesi.Collections.Generic;
using FluentNHibernate.Mapping;
using Job.FluenCore.Article.Model;

namespace Job.FluenCore.Article.Mapping
{
    public class NewsMap : ClassMap<News>
    {
        public NewsMap()
        {
            Table("[t_News]");
            Id(p => p.Id).GeneratedBy.Identity();
            Map(p => p.ClassId).Not.Nullable().Default("0");
            Map(p => p.Title).Not.Nullable().Length(255);
            Map(p => p.TitleColor).Nullable().Length(10);
            Map(p => p.TitleSub).Nullable().Length(255);
            Map(p => p.Content).Nullable().CustomSqlType("text");
            Map(p => p.Author).Nullable().Length(50);
            Map(p => p.Introduction).Nullable().Length(1000);

            Map(p => p.PageTitle).Nullable().Length(100);
            Map(p => p.PageKeywords).Nullable().Length(100);
            Map(p => p.PageDescription).Nullable().Length(255);

            Map(p => p.IsTop).Not.Nullable().Default("0");
            Map(p => p.IsRecommend).Not.Nullable().Default("0");
            Map(p => p.IsNoComment).Not.Nullable().Default("0");
            Map(p => p.Star).Not.Nullable().Default("0");
            Map(p => p.ContentOrder).Not.Nullable().Default("0");
            Map(p => p.ContentUrl).Nullable().Length(255);
            Map(p => p.IndexImage).Not.Nullable().Default("0");

            Map(p => p.Visits).Not.Nullable().Default("0");
            Map(p => p.AddTime).Not.Nullable().Default("getdate()");
            Map(p => p.EditTime).Not.Nullable().Default("getdate()");
            Map(p => p.ContentStatus).CustomType<NewAuditType>();

            /*
            References<NewsClass>(p => p.Class)
                .LazyLoad()
                .Column("ClassID")
                .Cascade.All();
            
            HasMany<NewsComments>(p => p.Comments)
                .AsSet().LazyLoad()
                .Inverse() //    Inverse="false"(默认):父实体负责维护关联关系     Inverse="true":子实体负责维护关联关系
                .KeyColumn("NewsID")
                .Cascade.All();

            HasMany<NewsFile>(p => p.Files)
                .AsSet().LazyLoad()
                .Inverse() //    Inverse="false"(默认):父实体负责维护关联关系     Inverse="true":子实体负责维护关联关系
                .KeyColumn("NewsID")
                .Cascade.All();
            */
        }
    }
}
映射
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using Webdiyer.WebControls.Mvc;

using Job.FluenCore.Common;
using Job.FluenCore.DateFactory;
using Job.FluenCore.Article.Mapping;
using Job.FluenCore.Article.Model;

namespace Job.FluenCore.Article.Repository
{
    #region Interface
    public interface INewsRepository : IRepositoryBase<News>
    {
        void UpdateHitClick(int Id);
    }
    #endregion

    public class NewsRepository : RepositoryBase<News>, INewsRepository
    {
        public NewsRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }

        public void UpdateHitClick(int Id)
        {
            var s = "update [t_News] set Visits=Visits+1 whre Id=:f1";

            base.CreateSQLQuery(s)
                .SetInt32("f1", Id)
                .ExecuteUpdate();
            //base.Commit();
        }
    }
}
数据工厂
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Data.Entity.Validation;

using Webdiyer.WebControls.Mvc;

using Job.FluenCore.Common;
using Job.FluenCore.DateFactory;
using Job.FluenCore.Article.Model;
using Job.FluenCore.Article.Repository;

namespace Job.FluenCore.Article.Service
{
    public interface INewsService : IServiceBase<INewsRepository>
    {
        void UpdateHitClick(int Id, string Ip);
    }

    public class NewsService : ServiceBase<INewsRepository>, INewsService
    {
        public NewsService(IUnitOfWork _unitwork, INewsRepository _repository)
            : base(_unitwork, _repository)
        { 
        }

        public void UpdateHitClick(int Id, string Ip)
        {
            base.Repository().UpdateHitClick(Id);

            /*
            var s = "update [t_News] set Visits=Visits+1,ip=:f2 whre Id=:f1";            
            base.Repository().CreateSQLQuery(s)
                .SetInt32("f1", Id)
                .SetString("f2", Ip)
                .ExecuteUpdate();
            base.Repository().Commit();
            */
        }

    }
}
数据服务
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

using Autofac;

using Job.FluenCore.Article.Mapping;
using Job.FluenCore.Article.Model;
using Job.FluenCore.Article.Repository;
using Job.FluenCore.Article.Service;

namespace Job.FluenCore.Article.Modules
{
    public class NewsModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("Job.FluenCore.Article.Modules ContainerBuilder");
            }

            builder.RegisterType<NewsService>().As<INewsService>().InstancePerLifetimeScope();
            builder.RegisterType<NewsRepository>().As<INewsRepository>().InstancePerLifetimeScope();

            builder.RegisterType<NewsClassService>().As<INewsClassService>().InstancePerLifetimeScope();
            builder.RegisterType<NewsClassRepository>().As<INewsClassRepository>().InstancePerLifetimeScope();


            base.Load(builder);
        }

        public System.Reflection.Assembly GetAssembly()
        {
            return System.Reflection.Assembly.GetExecutingAssembly();
        }
    }
}
注册服务
namespace Job.FluenCore.DateFactory
{
    public interface IRepositoryBase<T> where T : class
    {
        /// <summary>
        /// 提交事务
        /// </summary>
        void Commit();

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsNowSave"></param>
        /// <returns></returns>
        T Add(T entity, bool IsNowSave = true);

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsNowSave"></param>
        void Update(T entity, bool IsNowSave = true);

        void SaveOrUpdate(T entity, bool IsNowSave = true);

        void Delete(T entity);
        void Delete(int Id, bool Load = false);
        void Delete(Expression<Func<T, bool>> where);

        T GetById(int Id);
        T GetById(string Id);

        /// <summary>
        /// 根据条件获得模型 Linq语句
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        T Get(Expression<Func<T, bool>> where);

        /// <summary>
        /// 支持 selector where查询
        /// var list= GetMany(o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        T Get(Expression<Func<T, bool>> where, Expression<Func<T, T>> selector);

        /// <summary>
        /// 支持 select where orderby查询
        /// var list= GetMany().Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        IQueryable<T> GetMany();

        /// <summary>
        /// 支持 select orderby查询
        /// var list= GetMany(o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        IQueryable<T> GetMany(Expression<Func<T, bool>> where);

        /// <summary>
        /// 支持 where查询
        /// var list= GetList(o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        PagedList<T> GetList(Expression<Func<T, bool>> where, int pagesize, int pageindex);

        /// <summary>
        /// 支持 select where查询
        /// var list= GetList(o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        PagedList<T> GetList(Expression<Func<T, bool>> where, Expression<Func<T, T>> select, int pagesize, int pageindex);

        /// <summary>
        /// 支持 select where查询
        /// var list= GetList(o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        PagedList<T> GetList(Expression<Func<T, bool>> where, Expression<Func<T, T>> select, Func<T, string> orderName, string sortOrder, int pagesize, int pageindex);

        /// <summary>
        /// 支持 select where查询
        /// var list= GetForModel[T](o => o.Id > 0).Select(o => o).OrderByDescending(o=>o.AddTime).ToPagedList(pageindex, pagesize);
        /// </summary>
        IQueryable<TModel> GetForModel<TModel>();

        /// <summary>
        /// 支持NHibernate语句,查询、更新、删除
        /// eg .CreateCriteria().add(Expression.like("name", "Fritz%")).add( Expression.between("weight", minWeight, maxWeight))
        /// </summary>
        ICriteria CreateCriteria();

        /// <summary>
        /// 支持NHibernate语句,查询、更新、删除
        /// eg .CreateCriteria().add(Expression.like("name", "Fritz%")).add( Expression.between("weight", minWeight, maxWeight))
        /// </summary>
        ICriteria CreateCriteria(string entityName);
        
        /// <summary>
        /// 支持 hql,参数,查询、更新、删除\ 注意不是SQL
        /// hibernate 中createQuery与createSQLQuery两者区别是:前者用的hql语句进行查询,后者可以用sql语句查询|
        /// eg .CreateQuery("from Customer c where c.Name.Firstname=:fn and c.Name.Lastname=:ln").SetString("fn", firstname).SetString("ln", lastname)
        /// </summary>
        IQuery CreateQuery(string queryString);

        /// <summary>
        /// 支持 SQL、参数,查询、更新、删除  更新语句请加 ExecuteUpdate|
        /// 注意:需使用正确的 数据表结构字段 
        /// eg CreateSQLQuery("select ID from News where id=:f1 and IsTop>5").SetString("f1", firstname) \ 
        /// eg CreateSQLQuery("{Call sp_Login(?,?) }").SetString(0, "admin").SetString(1, "admin");
        /// </summary>
        ISQLQuery CreateSQLQuery(string queryString);
             
        /// <summary>
        /// 分页查询(sql分页方式) 统计
        /// 注意:需使用正确的 数据表结构字段 
        /// </summary>
        System.Collections.Generic.IList<TModel> GetListForPaging<TModel>(string tableName, int pageNumber, int pageSize, string orderName, string sortOrder, string CommandText, out int Count);

        /// <summary>
        /// 分页查询(sql分页方式) 不统计
        /// 注意:需使用正确的 数据表结构字段 
        /// </summary>
        System.Collections.Generic.IList<TModel> GetListForPaging<TModel>(string tableName, int pageNumber, int pageSize, string orderName, string sortOrder, string CommandText);

        /// <summary>
        /// 原生SQL关联查询
        /// 注意:需使用正确的 数据表结构字段 
        /// </summary>
        System.Collections.Generic.IList<TModel> GetListForPaging<TModel>(string strQuery);


        /// <summary>
        /// 原生SQL关联查询
        /// 注意:需使用正确的 数据表结构字段 
        /// </summary>
        System.Data.DataSet GetDataSet(string strQuery);

        /// <summary>
        /// 计算总个数(分页)
        /// </summary>
        int GetCount(string tableName, string commandText);
    }
数据工厂基础接口
using System;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.ComponentModel;

using Job.FluenCore.Ceche;
using Webdiyer.WebControls.Mvc;
using DotNet.Common;
using Job.FluenCore.Common;
using Job.FluenCore.Common.MVCFormwork;

using Job.FluenCore.Article;
using Job.FluenCore.Article.Model;
using Job.FluenCore.Article.Repository;
using Job.FluenCore.Article.Service;

namespace Job.Web.Controller
{
    public class NewsController : BaseWebController
    {
        protected readonly INewsService _NewsService;
        protected readonly INewsClassService _NewClassService;
        
        public NewsController(INewsService NewsService, INewsClassService NewClassService)
        {
            this._NewsService = NewsService;
            this._NewClassService = NewClassService;
        }


        #region web
        [HttpGet]
        public virtual ActionResult Index(int? page, int intPid = 0, int intStatus = 1)
        {
            //int _page = page ?? GetPageIndex();
            //var stus = (NewsClassStatusType)intStatus;
            //var where = PredicateExtensions.True<News>();
            //if (intStatus == 0 || intStatus == 1) { where = where.And(p => p.Status == stus); }
            //if (intPid > 0) { where = where.And(p => p.ParentId == intPid); }

            //var list = _NewsService
            //    .Repository()
            //    .GetList(where, GetPageSize(), _page);

            //PageData();

            return View();
        }

        [HttpGet]
        public virtual ActionResult Detail(int id, int intStatus = 1)
        {
            //var data = _NewsService.Repository().GetById(id);
            //data = data ?? new News();
            //PageData();
            return View();
        }

        #endregion


        #region admin
        /* true 显示错误; false 继续 */
        [LoginAllowView]
        [Description("[详细信息]检查是否存在(add,Update必备)")]
        public ActionResult CheckExist()
        {
            var action = QueryString.Request["action"];
            var ID = QueryString.Request["ID"].GetNum(0);
            var val = QueryString.Request[action];
            var b = false;
            if (!val.IsNullOrWhiteSpace())
            {
                switch (action)
                {
                    case "ContentUrl":
                        b = _NewsService.Repository().GetMany(p => p.Id != ID && p.ContentUrl == val).Any();
                        break;
                }
            }
            b = !b;
            return Content(b.ToString().ToLower());
        }


        [Description("[Index主页]新闻管理")]
        [ViewPage]
        [DefaultPage]
        public ActionResult AdminIndex(int Type = 0)
        {
            var CurrentTypeID = Type;
            var titel = typeof(NewsClassType).GetEnumDictionaryA().GetValue(CurrentTypeID);
            titel = titel ?? "文章";
            ViewBag.Title = titel + "管理";
            ViewBag.CurrentID = CurrentTypeID;
            return View();
        }

        [ViewPage]
        [Description("[详细信息]新闻详细信息(add,Update,Detail必备)")]
        public ActionResult AdminDetail()
        {
            ViewBag.IsView = (QueryString.Request["IsView"] == "1") ? 1 : 0;
            ViewBag.CurrentID = QueryString.Request["ID"].GetNum(0);
            return View();
        }

        [Description("[Get Json]获取新闻Json")]
        [LigerUIExceptionResult]
        public ActionResult AdminGet(int? id)
        {
            var _id = id ?? 0;
            var data = _NewsService.Repository().Get(o => o.Id == _id);
            data = data ?? new News();
            return this.JsonFormat(data, true, "获取[新闻]");
        }

        [Description("[系统]添加动作")]
        [LigerUIExceptionResult]
        public ActionResult AdminAdd()
        {
            News model = new News();
            this.TryUpdateModel(model);
            model.Id = 0;
            model.AddTime = model.AddTime == null ? DateTime.UtcNow : model.AddTime;
            model.EditTime = model.AddTime == null ? DateTime.UtcNow : model.EditTime;
            return AdminSave(model);
        }

        [Description("[系统]修改动作")]
        [LigerUIExceptionResult]
        public ActionResult AdminUpdate()
        {
            News model = new News();
            this.TryUpdateModel(model);
            model.AddTime = model.AddTime == null ? DateTime.UtcNow : model.AddTime;
            model.EditTime = model.AddTime == null ? DateTime.UtcNow : model.EditTime;
            return AdminSave(model);
        }

        [Description("[Delete]页面删除请求")]
        [LigerUIExceptionResult]
        public ActionResult AdminDelete(int Id)
        {
            var status = true;
            _NewsService.Repository().Delete(Id);
            return this.JsonFormat(null, status, "删除[新闻]");
        }
        
        [Description("[gridRequest请求]获取新闻")]
        [LoginAllowView]
        public ActionResult AdminGetGrid()
        {
            var gridRequest = new LigerUIGridRequest(HttpContext);
            var where = gridRequest.Where;
            var parms = FilterHelper.GetFilterTanslateQuery(ref where);

            int Count = _NewsService.Repository().GetMany()
                .Where(where, parms)
                .Count();

            var data = _NewsService.Repository().GetMany()
                .Where(where, parms)
                .OrderBy(gridRequest.SortName + " " + gridRequest.SortOrder)
                .Skip((gridRequest.PageNumber - 1) * gridRequest.PageSize)
                .Take(gridRequest.PageSize)
                .Select(o => new
                {
                    Id = o.Id,
                    Title = o.Title,
                    TitleColor = o.TitleColor,
                    EditTime = o.EditTime,
                    ContentUrl = o.ContentUrl,
                    ContentStatus = o.ContentStatus,
                    IndexImage = o.IndexImage,
                    IsNoComment = o.IsNoComment,
                    IsRecommend = o.IsRecommend,
                    IsTop = o.IsTop,
                    Visits = o.Visits,
                    Star = o.Star,
                    AddTime = o.AddTime,
                    //TypeId = o.TypeId,
                    ClassId = o.ClassId
                })
                .ToList();

            var grid = new LigerUIGrid();
            grid.Rows = data;
            grid.Total = Count;
            return this.JsonFormat(grid);
        }
        #endregion

        #region heper

        [NonAction]
        public ActionResult AdminSave(News model)
        {
            var status = SaveNewsClass(model, model.Id > 1);
            return this.JsonFormat(null, status, "保存[新闻分类]");
        }

        public bool SaveNewsClass(News model, bool IsEdit = true)
        {
            if (model == null) { return false; }

            model.AddTime = DateTimeHelper.DateTimeYeas(model.AddTime);
            model.EditTime = DateTimeHelper.DateTimeYeas(model.EditTime);
            model.ClassId = model.ClassId < 0 ? QueryString.Request["ClassId"].GetNum(0) : model.ClassId;

            if (IsEdit)
            {
                _NewsService.Repository().Update(model);
            }
            else
            {
                _NewsService.Repository().Add(model);
            }
            return true;
        }
        #endregion
    }
}
新闻资讯操作实例


同时我们对Linq的扩展也可以流畅的对数据操作。


 

不过这里也有一些问题需要改进;
1 目前的动态自定义查询问题,
让使用者自己可以控制查询字段、条件、显示结果字段、排序等;(特别是在管理后台,jquery + ligerUI 结合使用, 管理者可以按需查询等, )
如:
_NewsService.Repository().GetMany()
                .Where("条件")
                .OrderBy("id desc")
                .Take(10)
                .Skip(10)
                .Select("New(Id,Title)");

2 跨表问题(目前可用试图、存储过程处理);

3 数据验证问题;

4 结构关系的调整处理。

未完。。。。 
先下班了。。。 晚上再写。


posted @ 2013-05-20 18:26  colvinliu  阅读(1881)  评论(7编辑  收藏  举报