Today, it took half a day to add the MongoDB-based Warehousing implementation to the byteart retail case. Readers can directly clone the latest code from the byteart retail code library to use the MongoDB-based Warehousing implementation.
Implementation step 1. refactor the byteartretail. domain. repositories directory structure
This step does not need to be done, but because the structure has not been well planned before, all the warehousing implementations based on Entity Framework are placed under the root directory. Now we have moved these warehousing implementations to the entityframework directory, and modified the Web. config file of the namespace and the byteartretail. Services Project. The structure after modification is as follows:
2. MongoDB-based Warehousing and context
In the in-depth analysis of byteart retail case: repository and its context, I have introduced in detail the design and implementation of warehousing and its context in the byteart retail case, therefore, it is very easy to implement a MongoDB warehouse on an existing framework. The specific implementation method is not described here. You can refer to the source code in this article, it took me less than an hour to complete the process. The directory structure after implementation is as follows:
3. migrate data from SQL localdb to MongoDB
This part took me some time. For the sake of simplicity, I wrote some console code myself. The basic idea is: Read the object in entityframeworkrepository first, and then use the aggregation root as the unit, use mongodbrepository to write data to MongoDB in sequence. Some minor issues are encountered during writing. The most important thing to note is that salesorder is aggregated in our salesline object, while salesorder itself aggregates salesline, this causes loop reference. Therefore, MongoDB reports an error (EF does not report an error because EF uses the delayed Loading Function to obtain salesline information). To solve this problem, you need to configure the MongoDB class map as follows:
BsonClassMap.RegisterClassMap<SalesLine>(s =>{ s.AutoMap(); s.SetIgnoreExtraElements(true); s.UnmapProperty<SalesOrder>(p => p.SalesOrder); // bypass circular reference.});
In addition, we need to use the aggregated root ID as the objectid of MongoDB and want the date and time to be stored in the local time format. Therefore, I have developed two Convention profiles, two static methods are added to mongodbrepositorycontext so that the application can call this static method at startup to complete relevant settings:
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<IConvention> 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. Modify the global. asax. CS File
In the global. asax. CS file, locate the application_start method and add the bootstrapper call to this method: mongodbbootstrapper. Bootstrap ();.
Of course, for the sake of simplicity, I also introduced a mongodbbootstrapper class to call the above registerconventions method to register the Convention profile. It also includes the registration of class map, no code will be posted here. After completing the above four steps, the preparations will be completed.
Enable MongoDB warehousing and its context
After the preparation is complete, let's start to enable MongoDB warehousing. Because I have completed data migration, I already have the byteartretail database in my MongoDB database. After cloning the latest version of the code, you must first install the MongoDB service, and then restore the byteartretail database in the byteart procedure. For example:
mongorestore -d ByteartRetail c:\ByteartRetail
After the database is restored, you can list the byteartretail database at the MongoDB prompt:
Next, modify the Web. config file under byteartretail. Services, comment out the Entity Framework repository and its context configuration section in the Unity configuration section, and enable the MongoDB repository and its context configuration, as shown below:
Okay. Now we start the site, and we can't see any changes from the front-end perspective, but byteart retail is already using MongoDB as the data persistence mechanism.
Note: if you do not use the default configuration when installing MongoDB (for example, you have changed the MongoDB port settings), you can modify byteartretail. domain. repositories. mongoDB. mongodbrepositorycontextsettings class, which configures MongoDB based on your actual situation. For detailed configuration instructions, see the annotations in this class.
Summary
This article is also an additional topic in the byteart retail case series. It aims to verify the scalability of the storage and its context in the byteart retail case. Experiments show that the current framework design can directly add support for other data persistence solutions without modifying any existing components, all we have to do is inherit several classes, implement several interfaces, and then modify the configuration information. It took me less than half a day to complete the entire process. Of course, the byteart retail project itself is not large, but it still gives us good inspiration: good architecture design can greatly reduce the waste of team resources and reduce the chance of errors. It also provides some support for system operation: we can allow a team to develop a component separately, after the development and testing are completed, the new implementation can be replaced on the basis that the system operation is not limited. Therefore, a good architecture design will have a significant impact on project management.