Summary of e-commerce system architecture (1)

         Recently, he has led the design and development process of an e-commerce system, including the whole process of preliminary analysis and design, framework construction, specific development of functional modules (mainly responsible for online payment), deployment and maintenance after successful launch, and operation and maintenance strategies.

Although this system is not a super-large e-commerce system with hundreds of millions of concurrent operations, the main members of the team have many years of development experience and experience in e-commerce. Although the system design is small, it has all the internal organs.

System clients include ios, android, H5, WeChat applet, .net web api + sql server in the background, Alibaba Cloud for reading and writing image resources, redis for caching, and some third-party payment platforms for payment , and Alipay, WeChat, etc. . . . There are many technical points. To be honest, the technologies used in the development of general application systems are basically used, and many pits have been encountered. Therefore, I feel that it is necessary to summarize the code inside, which is of great reference for future system development, especially the development of similar projects. Since I did not participate in the development of the front-end, I mainly focus on the .nt background architecture.

        Since it is .nt mvc web api, EF is chosen as the orm component. The program layered architecture is divided into: data layer DAL and IDAL, business layer BLL and IBLL, Entity (entity definition), WebAPI, and a Utility project has been built to accommodate some business-independent and reusable functional codes As well as third-party open source code, there are also two separate solutions, a web api project named thirdparty, which is used to interface with third-party platforms, including sending SMS verification codes to the SMS platform, uploading pictures to Alibaba Cloud, Check the logistics status of express orders, and push messages to the push platform (Aurora, WeChat official account). The other is a windows service program that is used to perform automated work tasks.

Described separately below.

1. DAL. Mainly responsible for encapsulating the underlying data operations on EF. There is a piece of code that implements the singleton mode for EF's DBContext, which I extracted from the Internet at that time. The code is as follows

public class DbContextFactory
    {
        public static WinLinkContext Create()
        {
            WinLinkContext dbContext = CallContext.GetData("DbContext") as WinLinkContext;
            if (dbContext == null)
            {
                dbContext = new WinLinkContext();
                CallContext.SetData("DbContext", dbContext);
            }
            return dbContext;
        }
    }

  In fact, when I first used EF, I remember that the official documents advocated that dbcontext is ready to use and sold, in the form of (using WinLinkContext = new WinLinkContext() ){...}, it is necessary to instantiate only one dbcontext and cache it down, does this improve performance and save resources? At the beginning, due to the tight schedule of the project, I didn't think much about it. I thought that this was a mature code used by others, or an example of a blog post by a big coffee, so I should not be wrong. As a result, there was still a problem. When a colleague a wrote the log processing module, he also called this DbContextFactory.Create() , the original intention was to record the information when the exception occurred to the database, but because the business code shared a dbcontext, the problem came. For example, a colleague b wrote a few lines of add/update EF code, and then wrote a few lines of other code, but the savechanges have not been executed yet, but these lines of other codes have bugs and cause exceptions, so the logs are captured, and the log module will Use ef to insert log information and execute savechanges. At this time, the key point is that this savechanges will submit the updated content of the entire dbcontext to the database! So even the log module reported an error, and the error message was the code content of colleague b. Of course, some readers will say that the log module should be opened independently and should not be mixed with the business. Indeed, we also opened it independently later. But this example shows that there is a big problem with dbcontext using the singleton mode. I think it should follow the official Microsoft example, which is sold immediately after use. Even if you want to cache, at least each module is opened independently, and you cannot use the only one for the entire application. For example, slightly change the above code, read and write different dbcontext according to the name.

 public  class DbContextFactory
    {
        public static WinLinkContext Create(string dbName)
        {
            WinLinkContext dbContext = CallContext.GetData(dbName) as WinLinkContext;
            if (dbContext == null)
            {
                dbContext = new WinLinkContext();
                CallContext.SetData(dbName, dbContext);
            }
            return dbContext;
        }
    }

There is also a BaseDAL class, which is used to encapsulate conventional methods such as addition, deletion, modification, and paging. The code is roughly as follows (the db object in it is the dbcontext mentioned above):

  public T Add(T t) 
        {
            return db.Set<T>().Add(t);
        }

        public void Update(T t) 
        {
            db.Set<T>().AddOrUpdate(t);
        }

        public void Delete(T t) 
        {
            db.Set<T>().Remove(t);
        }
        public bool Delete(string id)
        {
            var entity = db.Set<T>().Find(id);
            if (entity == null)
            {
                return false;
            }
            db.Set<T>().Remove(entity);
            return true;
        }

        public int Delete(string[] ids)
        {
            foreach (var item in ids)
            {
                var entity = db.Set<T>().Find(item); // If the entity is already in memory, then take it directly from memory, if there is no tracking entity in memory, then query the database. 
                db.Set<T> ().Remove(entity);
            }
            return ids.Count();
        }

        public T Find(Expression<Func<T, bool>> findLambda)
        {
            return db.Set<T>().FirstOrDefault(findLambda);
        }

        public T Find(string id)
        {
            return db.Set<T>().Find(id);
        }

        public IQueryable<T> Where(Expression<Func<T, bool>> whereLambda)
        {
            return db.Set<T>().Where(whereLambda);
        }

        public IQueryable<T> GetByPage<Type>(int pageSize, int pageIndex, out int total, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Type>> orderByLambda, bool isAsc)
        {
            var queryData = db.Set<T>().Where(whereLambda);

            // Whether ascending 
            if (isAsc)
            {
                queryData = queryData.OrderBy(orderByLambda);
            }
            else
            {
                queryData = queryData.OrderByDescending(orderByLambda);
            }

            total = queryData.Count();
            if (total > 0)
            {
                if (pageIndex <= 1)
                {
                    queryData = queryData.Take(pageSize);
                }
                else
                {
                    queryData = queryData.Skip((pageIndex - 1) * pageSize).Take(pageSize);
                }

            }

            return queryData;
        }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325078998&siteId=291194637