你的位置:首页 > ASP.net教程

[ASP.net教程]新做的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 结构关系的调整处理。

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