设为首页 收藏本站
查看: 901|回复: 0

[经验分享] 深度剖析Byteart Retail案例:基于MongoDB的仓储实现

[复制链接]

尚未签到

发表于 2015-7-5 14:05:39 | 显示全部楼层 |阅读模式
  今天花了半天时间,向Byteart Retail案例加入了基于MongoDB的仓储实现,读者朋友可以直接从Byteart Retail的代码库克隆最新代码来使用基于MongoDB的仓储实现。
  实现步骤
  1、重构ByteartRetail.Domain.Repositories目录结构
  本来这一步是不需要做的,但是因为之前没有把结构规划好,所以所有基于Entity Framework的仓储实现都放在了根目录下。现在把这些仓储的实现都移到了EntityFramework目录中,同时修改了命名空间和ByteartRetail.Services项目的web.config文件。改完后结构如下:
DSC0000.png
  2、实现基于MongoDB的仓储和上下文
  在《深度剖析Byteart Retail案例:仓储(Repository)及其上下文(Repository Context)》一文中,我已经详细介绍了Byteart Retail案例中仓储及其上下文的设计和实现,因此,在已有的框架上再实现一个MongoDB的仓储是非常容易的事情,具体实现方式在此也不多做说明了,可以结合这篇文章并参考源代码,整个过程只花了我不到一个小时的时间。实现后的目录结构如下:
DSC0001.png
  3、将SQL LocalDB中的数据迁移到MongoDB中
  这部分花了我一些时间,为了简单起见,我还是自己写了一些控制台代码,基本思路是:先用EntityFrameworkRepository将对象读入,然后以聚合根为单位,使用MongoDBRepository依次写入MongoDB。写入的时候遇到了一些小问题,其中最需要注意的就是,在我们的SalesLine对象中聚合了SalesOrder,而SalesOrder本身又聚合了SalesLine,这就造成了循环引用,因此MongoDB会报错的(EF不会报错,因为EF采用了延迟加载功能来获取SalesLine信息),为了解决这个问题,需要配置MongoDB的Class Map,如下:
BsonClassMap.RegisterClassMap(s =>
{
s.AutoMap();
s.SetIgnoreExtraElements(true);
s.UnmapProperty(p => p.SalesOrder); // bypass circular reference.
});
  此外,我们需要用聚合根的ID作为MongoDB的objectID,并希望日期时间以本地时间格式存储,因此,我另外开发了两个Convention Profile,并在MongoDBRepositoryContext中增加了两个静态方法,以便应用程序在启动的时候能够调用这个静态方法完成相关设置:

public class UseLocalDateTimeConvention : IMemberMapConvention
{
public void Apply(BsonMemberMap memberMap)
{
IBsonSerializationOptions options = null;
switch (memberMap.MemberInfo.MemberType)
{
case MemberTypes.Property:
PropertyInfo propertyInfo = (PropertyInfo)memberMap.MemberInfo;
if (propertyInfo.PropertyType == typeof(DateTime) ||
propertyInfo.PropertyType == typeof(DateTime?))
options = new DateTimeSerializationOptions(DateTimeKind.Local);
break;
case MemberTypes.Field:
FieldInfo fieldInfo = (FieldInfo)memberMap.MemberInfo;
if (fieldInfo.FieldType == typeof(DateTime) ||
fieldInfo.FieldType == typeof(DateTime?))
options = new DateTimeSerializationOptions(DateTimeKind.Local);
break;
default:
break;
}
memberMap.SetSerializationOptions(options);
}
public string Name
{
get { return this.GetType().Name; }
}
}
public class GuidIDGeneratorConvention : IPostProcessingConvention
{
public void PostProcess(BsonClassMap classMap)
{
if (typeof(IEntity).IsAssignableFrom(classMap.ClassType) &&
classMap.IdMemberMap != null)
{
classMap.IdMemberMap.SetIdGenerator(new GuidGenerator());
}
}
public string Name
{
get { return this.GetType().Name; }
}
}
public static void RegisterConventions(bool autoGenerateID = true, bool localDateTime = true)
{
RegisterConventions(autoGenerateID, localDateTime, null);
}
public static void RegisterConventions(bool autoGenerateID, bool localDateTime,
IEnumerable additionConventions)
{
var conventionPack = new ConventionPack();
conventionPack.Add(new NamedIdMemberConvention("id", "Id", "ID", "iD"));
if (autoGenerateID)
conventionPack.Add(new GuidIDGeneratorConvention());
if (localDateTime)
conventionPack.Add(new UseLocalDateTimeConvention());
if (additionConventions != null)
conventionPack.AddRange(additionConventions);
ConventionRegistry.Register("DefaultConvention", conventionPack, t => true);
}
4、修改Global.asax.cs文件
  在Global.asax.cs文件中,找到Application_Start方法,在这个方法中加入bootstrapper的调用:MongoDBBootstrapper.Bootstrap();。
  当然,为了简单起见,我还引入了一个MongoDBBootstrapper类,用来调用上面的RegisterConventions方法对Convention Profile进行注册,同时还包含了对Class Map的注册,在此就不贴代码了。完成以上四步以后,准备工作就做好了。

启用MongoDB仓储及其上下文
  准备工作做好以后,就让我们开始启用MongoDB仓储吧。由于我上面已经完成了数据迁移,因此,在我的MongoDB数据库中已经有了ByteartRetail数据库。读者朋友在完成最新版本代码克隆之后,请先自行安装MongoDB服务,然后,在Byteart Retail源代码目录的demo_data目录下,有个ByteartRetail.zip的压缩包,将其解压到你的本地磁盘,然后,进入MongoDB的bin目录,使用mongorestore.exe程序恢复ByteartRetail数据库。比如:

mongorestore -d ByteartRetail c:\ByteartRetail
  完成数据库恢复之后,你将可以在mongoDB的提示符下列出ByteartRetail数据库:
DSC0002.png
  下一步,修改ByteartRetail.Services下的web.config文件,将unity配置部分中的Entity Framework仓储及其上下文的配置部分注释掉,然后启用MongoDB仓储及其上下文的配置,如下:
DSC0003.png
  OK,现在启动站点,从前台的角度我们基本上看不到任何变化,但此时Byteart Retail已经在使用MongoDB作为数据持久化机制了。
DSC0004.png
  最后说明一下:如果你安装MongoDB的时候不是使用的默认配置(比如你改过MongoDB的端口等设置),那么,你可以修改ByteartRetail.Domain.Repositories.MongoDB.MongoDBRepositoryContextSettings 类,在这个类中根据你的具体情况对MongoDB进行配置。配置的详细说明请参考该类中的注释。

总结
  本文也算是《深度剖析Byteart Retail案例》系列文章的一个题外篇,主要目的就是为了验证在Byteart Retail案例中,仓储及其上下文的可扩展性。实验证明,目前的框架设计能够在不改动任何已有组件的基础上,直接新增对其它数据持久化方案的支持,我们所要做的仅仅就是继承几个类、实现几个接口,然后修改一下配置信息。整个过程花了我一个人不到半天的时间,当然,Byteart Retail项目本身规模也不大,但仍然给了我们很好的启示:良好的架构设计能够大幅度降低团队资源的浪费,并且减小出错的几率,同时还对系统运营提供了一定的支持:我们可以让某个团队单独地开发一个组件,在完成开发和测试之后,可以在不大范围影响系统运行的基础上将新的实现替换进去。因此,良好的架构设计将会对项目的管理带来重大影响。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83404-1-1.html 上篇帖子: Node+Express+MongoDB+Socket.io搭建实时聊天应用实战教程(一) 下篇帖子: 深入浅出MongoDB(一)NoSQL
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表