C# discuss the problems of the c# project I wrote

The reason for this article is that yesterday we planned to release the code of this article into a nuget package for internal use. But the person in charge asked questions, and I think his view is wrong. But my eloquence is not good. I can't win. Copy all the codes of this project into this article. You can have a look and provide the following opinions:

1, Project structure

The nuget package referenced in the screenshot was written by our person in charge. This package encapsulates the basic functions based on FreeSql. My project design is based on his nuget package, which is encapsulated once, so that users can use it more conveniently.

2, Project code

2.1 DbProvider.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <inheritdoc cref="IDbProvider" path="/summary"/>
    public abstract class DbProvider : IDbProvider
    {
        /// <inheritdoc/>
        public IRepository Repository { get; protected set; }

        /// <summary>
        ///Represents database code first
        /// </summary>
        protected ICodeFirst CodeFirst { get; set; }

        /// <summary>
        /// <inheritdoc cref="DbProvider" path="/summary"/>
        /// </summary>
        protected DbProvider() { }

        /// <inheritdoc/>
        public virtual void CreateDatabase(string dbPath) { }

        /// <inheritdoc/>
        public virtual void CreateEntity(Action<ICodeFirst> action = null)
        {
            if (this.CodeFirst == null)
            {
                throw new InvalidOperationException("Please initialize the database first");
            }

            action?.Invoke(this.CodeFirst);

            CodeFirst.InitDatabaseAsync();
        }
    }
}

 2.2 DbRuntime.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <summary>
    ///Represents the database runtime
    /// </summary>
    /// <creator>marc</creator>
    internal class DbRuntime
    {
        /// <inheritdoc cref="IDbProvider.Repository"/>
        public static IRepository Repository { get; internal set; }
    }
}

2.3 IDbBuilder.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <summary>
    ///Represents the database builder
    /// </summary>
    /// <creator>Marc</creator>
    internal interface IDbBuilder
    {
        /// <summary>
        ///Represents a database warehouse object
        /// </summary>
        IRepository Repository { get; }
    }
}

2.4 IDbProvider.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <summary>
    ///Represents a database drive
    /// </summary>
    /// <creator>marc</creator>
    public interface IDbProvider
    {
        /// <summary>
        ///An object that represents a database persistence operation
        /// </summary>
        IRepository Repository { get; }

        /// <summary>
        ///Create database
        /// </summary>
        /// <param name="dbPath"><inheritdoc cref="SqliteBuilder(string)" path="/param[@name='dbPath']"/></param>
        void CreateDatabase(string dbPath);

        /// <summary>
        ///Create entity
        /// </summary>
        ///< param name = "action" > create database entity < / param >
        void CreateEntity(Action<ICodeFirst> action = null);
    }
}

2.5 SqliteBuilder.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <summary>
    ///Represents the database builder for Sqlite
    /// </summary>
    /// <creator>marc</creator>
    internal class SqliteBuilder : IDbBuilder
    {
        /// <summary>
        ///Indicates the full path of the database file
        /// </summary>
        private readonly string _dbPath;
        /// <summary>
        ///Represents a FreeSql object
        /// </summary>
        private IFreeSql _freeSql;
        /// <summary>
        ///Represents a database warehouse object
        /// </summary>
        private IRepository _repository;
        /// <summary>
        ///Represents a database warehouse object
        /// </summary>
        public IRepository Repository => this._repository;

        /// <summary>
        ///Used for Sqlite database initialization
        /// </summary>
        ///< param name = "dbpath" > indicates the database path. The default location is the simulator under the current application directory (|DirectoryBase|) DB file < / param >
        internal SqliteBuilder(string dbPath)
        {
            this._dbPath = dbPath.Replace("|DirectoryBase|", AppDomain.CurrentDomain.BaseDirectory);
        }

        /// <summary>
        ///Create database
        /// </summary>
        public void Build()
        {
            this.CreateDirectory();
            this.CreateFreeSql();
            this.CreateRepository();
        }

        /// <summary>
        ///Create directory
        /// </summary>
        private void CreateDirectory()
        {
            if (!Directory.Exists(Path.GetDirectoryName(_dbPath)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(_dbPath));
            }
        }

        /// <summary>
        ///Create FreeSql object
        /// </summary>
        private void CreateFreeSql()
        {
            //Initialize FreeSql
            this._freeSql = new FreeSql.FreeSqlBuilder()
                .UseConnectionString(FreeSql.DataType.Sqlite, $"Data Source={this._dbPath}")
                .Build();
        }

        /// <summary>
        ///Create database warehouse object
        /// </summary>
        private void CreateRepository()
        {
            //Initialize ID generator
            Distributed.ID.IIDGenerator<long> idGenerator = new Distributed.ID.SnowFlakeIDGenerator(0, 0, 1, 2);
            //Create logger
            var logger = Logging.LoggerFactory.Instance.CreateLogger<FreeSqlRepository>();
            //Create persistence
            this._repository = new FreeSqlRepository(this._freeSql, idGenerator, logger);
        }
    }
}

2.6 SqliteDbProvider.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database
{
    /// <summary>
    ///Represents a database drive that uses Sqlite
    /// </summary>
    /// <creator>marc</creator>
    public class SqliteDbProvider : DbProvider, IDbProvider
    {
        /// <inheritdoc cref="DbProvider.Repository"/>
        private IRepository _repository;

        /// <inheritdoc cref="DbProvider.CodeFirst"/>
        private ICodeFirst _codeFirst;

        /// <summary>
        ///Database initialization
        /// </summary>
        /// <param name="dbPath"><inheritdoc cref="SqliteBuilder(string)" path="/param[@name='dbPath']"/></param>
        public override void CreateDatabase(string dbPath)
        {
            SqliteBuilder database = new SqliteBuilder(dbPath);
            database.Build();

            var repository = database.Repository;
            var codeFirst = ((ICodeFirst)database.Repository);

            Repository = repository;
            CodeFirst = codeFirst;

            DbRuntime.Repository = repository;

            _repository = repository;
            _codeFirst = codeFirst;
        }

        /// <summary>
        ///Database creation entity
        /// </summary>
        ///< param name = "action" > create database entity < / param >
        public override void CreateEntity(Action<ICodeFirst> action = null)
        {
            base.CreateEntity(action);
        }
    }
}

2.7 Repositories/IPager.cs

using Kintai.Entities;
using System.Collections.Generic;

namespace Kintai.Database.Repositories
{
    /// <summary>
    ///Represents data paging information
    /// </summary>
    /// <creator>marc</creator>
    public interface IPager<TEntity> where TEntity : Entity, new()
    {
        /// <summary>
        ///Represents a paging record
        /// </summary>
        IReadOnlyList<TEntity> Records { get; }
        /// <summary>
        ///Indicates the total number of records
        /// </summary>
        long TotalRecordCount { get; }
    }
}

2.8 Repositories/IStore.cs

using Kintai.Entities;
using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace Kintai.Database.Repositories
{
    /// <summary>
    ///Represents the base class for data persistence operations
    /// </summary>
    /// <creator>marc</creator>
    public interface IStore<TEntity> where TEntity : Entity, new()
    {
        /// <summary>
        ///Indicates adding or updating a record
        /// </summary>
        /// <param name="entity"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='entity']"/></param>
        Task<TEntity> InsertOrUpdateAsync(TEntity entity);

        /// <inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)"/>
        TEntity First(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default);

        /// <summary>
        ///Get a unique piece of data
        /// </summary>
        ///< param name = "predict" > indicates the query expression < / param >
        ///< param name = "includedetails" > indicates whether the level contains associated entities < / param >
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< exception CREF = "invalidoperationexception" > if there are multiple results, this exception will be thrown < / exception >
        ///< returns > only one piece of data is returned < / returns >
        Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default);

        /// <summary>
        ///Add data
        /// </summary>
        ///< param name = "entity" > indicates entity < / param >
        ///< param name = "cancelationtoken" > indicates that a task is canceled < / param >
        ///< returns > returns the newly added entity object < / returns >
        Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Add multiple pieces of data
        /// </summary>
        ///< param name = "entities" > indicates multiple entities < / param >
        ///< param name = "cancelationtoken" > indicates that a task is canceled < / param >
        ///< returns > returns the newly added entity object < / returns >
        Task<IEnumerable<TEntity>> InsertManyAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Delete data
        /// </summary>
        /// <param name="predicate"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='predicate']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns the deletion result. When it is < see langword = "1" / > it means success, and others are failures < / returns >
        Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Delete data
        /// </summary>
        ///< param name = "Id" > indicates the entity primary key ID < / param >
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns the deletion result. When it is < see langword = "1" / > it means success, and others are failures < / returns >
        Task<int> DeleteAsync(long id, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Delete data
        /// </summary>
        ///< param name = "IDS" > indicates multiple entity primary key IDS < / param >
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns the deletion result. When it is < see langword = "1" / > it means success, and others are failures < / returns >
        Task<int> DeleteManyAsync(IEnumerable<long> ids, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Update data
        /// </summary>
        /// <param name="entity"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='entity']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns the update result. When it is < see langword = "1" / > it means success, and others are failures < / returns >
        Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Update multiple data
        /// </summary>
        ///< param name = "entities" > indicates multiple entities < / param >
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns the update result. When it is < see langword = "1" / > it means success, and others are failures < / returns >
        Task<int> UpdateManyAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Get a unique piece of data
        /// </summary>
        /// <param name="id"><inheritdoc cref="DeleteAsync(long, CancellationToken)" path="/param[@name='id']"/></param>
        /// <param name="includeDetails"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='includeDetails']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > only one piece of data is returned < / returns >
        Task<TEntity> GetAsync(long id, bool includeDetails = true, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Get a unique piece of data
        /// </summary>
        /// <param name="predicate"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='predicate']"/></param>
        /// <param name="includeDetails"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='includeDetails']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > only one piece of data is returned < / returns >
        Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Fetch multiple entity data with paging
        /// </summary>
        /// <param name="predicate"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='predicate']"/></param>
        ///< param name = "PageIndex" > indicates the paging index < / param >
        ///< param name = "PageSize" > indicates the number of records per page < / param >
        /// <param name="includeDetails"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='includeDetails']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns multiple pieces of data < / returns >
        Task<IPager<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, int pageIndex = 0, int pageSize = 50, bool includeDetails = false, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Get multiple entity data with pagination and sorting
        /// </summary>
        /// <param name="predicate"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='predicate']"/></param>
        ///< param name = "PageIndex" > indicates the paging index < / param >
        ///< param name = "PageSize" > indicates the number of records per page < / param >
        ///< param name = "orderby" > indicates sorting < / param >
        /// <param name="includeDetails"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='includeDetails']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > returns multiple pieces of data < / returns >
        Task<IPager<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, Action<IOrderBy<TEntity>> orderBy, int pageIndex = 0, int pageSize = 50, bool includeDetails = false, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        ///Take the number of qualified entities
        /// </summary>
        /// <param name="predicate"><inheritdoc cref="FirstAsync(Expression{Func{TEntity, bool}}, bool, CancellationToken)" path="/param[@name='predicate']"/></param>
        /// <param name="cancellationToken"><inheritdoc cref="InsertAsync(TEntity, CancellationToken)" path="/param[@name='cancellationToken']"/></param>
        ///< returns > total quantity returned < / returns >
        Task<long> GetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken));
    }
}

2.9 Repositories/Pager.cs

using Kintai.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kintai.Database.Repositories
{
    /// <inheritdoc cref="IPager{TEntity}"/>
    public class Pager<TEntity> : IPager<TEntity>
        where TEntity : Entity, new()
    {
        /// <inheritdoc/>
        public IReadOnlyList<TEntity> Records { get; set; }
        /// <inheritdoc/>
        public long TotalRecordCount { get; set; }
    }
}

2.10 Repositories/Store~.cs

using Kintai.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kintai.Entities;
using System.Linq.Expressions;
using Kintai.Exception;
using System.Threading;
using Kintai.Database.Repositories;

namespace Kintai.Database.Repositories
{
    /// <inheritdoc cref="IStore{TEntity}"/>
    public class Store<TEntity> : IStore<TEntity> where TEntity : Entity, new()
    {
        /// <inheritdoc cref="IDbProvider.Repository"/>
        protected readonly IRepository Repository;

        /// <inheritdoc cref="RepositoryBase"/>
        public Store()
        {
            Repository = DbRuntime.Repository;
        }

        /// <inheritdoc/>
        public virtual async Task<TEntity> InsertOrUpdateAsync(TEntity entity)
        {
            TEntity oldEntity = await this.FirstAsync(q => q.Id == entity.Id);
            if (oldEntity == null)
            {
                return await this.InsertAsync(entity);
            }
            else
            {
                if (await this.UpdateAsync(entity) == 1)
                {
                    return entity;
                }
                else
                {
                    throw new KintaiException("Failed to update data");
                }
            }
        }

        /// <inheritdoc/>
        public virtual TEntity First(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            return this.FirstAsync(predicate, includeDetails, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
        }

        /// <inheritdoc/>
        public virtual async Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            return await this.GetAsync(predicate, includeDetails, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.InsertAsync(entity, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<IEnumerable<TEntity>> InsertManyAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.InsertManyAsync(entities, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.DeleteAsync(predicate);
        }

        /// <inheritdoc/>
        public virtual async Task<int> DeleteAsync(long id, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.DeleteAsync<TEntity>(id, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<int> DeleteManyAsync(IEnumerable<long> ids, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.DeleteManyAsync<TEntity>(ids, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.UpdateAsync(entity, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<int> UpdateManyAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.UpdateManyAsync(entities, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<TEntity> GetAsync(long id, bool includeDetails = true, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.GetAsync<TEntity>(id, includeDetails, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.GetAsync(predicate, includeDetails, cancellationToken);
        }

        /// <inheritdoc/>
        public virtual async Task<IPager<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, int pageIndex = 0, int pageSize = 50, bool includeDetails = false, CancellationToken cancellationToken = default(CancellationToken))
        {
            Pager<TEntity> pager = new Pager<TEntity>();
            var result = await this.Repository.GetListAsync(predicate, pageIndex, pageSize, includeDetails, cancellationToken);
            pager.Records = result.Records.AsReadOnly();
            pager.TotalRecordCount = result.TotalRecordCount;

            return pager;
        }

        /// <inheritdoc/>
        public virtual async Task<IPager<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, Action<IOrderBy<TEntity>> orderBy, int pageIndex = 0, int pageSize = 50, bool includeDetails = false, CancellationToken cancellationToken = default(CancellationToken))
        {
            Pager<TEntity> pager = new Pager<TEntity>();
            var result = await this.Repository.GetListAsync(predicate, orderBy, pageIndex, pageSize, includeDetails, cancellationToken);
            pager.Records = result.Records.AsReadOnly();
            pager.TotalRecordCount = result.TotalRecordCount;

            return pager;
        }

        /// <inheritdoc/>
        public virtual async Task<long> GetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Repository.GetCountAsync(predicate, cancellationToken);
        }
    }
}

3, About the use of code

3.1 if my encapsulation is used, its calling method is as follows

3.2 if the package of the responsible person is used, its calling method is as follows

IV. key points, the problems of this paper

I hope the person in charge will publish my project as nuget package. After reading it, the person in charge asked me the following questions:

(I refer to the author below)

1. The packaging results written by the person in charge can be used directly. I'll encapsulate another layer here. What's the significance?

2. If the user finds that he is using FreeSQL now, in case its performance is poor and the caller wants to change another one, how can I ask the caller to specify the new ORM framework he wants? That is, the caller does not want to use FreeSQL

3. I open CodeFirst of FreeSql to users' applications. It is highly coupled. In case other ones are not FreeSql, will you still have the exclusive object of CodeFirst? The meaning of this is shown in the figure below:

4. I encapsulated this. For multiple databases, multiple IRepository objects will be generated. Now I encapsulate only for the case of only one IRepository. What should I do if multiple databases are used? It refers to the following figure, which cannot be compatible with multiple databases:

5, I hope you can give me some comments on this project

Let's start with the results. There is no doubt that I ended up in failure on all the points he put forward. I didn't win. But when I got off work yesterday, I thought carefully on the road. Although I didn't win, my point of view should be right. There should be no problem with the code writing method. I'll list it here and let's comment on it:

About point 1: (the packaging results written by the person in charge can be used directly. I'll package another layer here. What's the significance?)

If you can ask me this, can I ask: EF Core itself has implemented the database. Although we use Sqlite, we can still use EF Core. Why does the person in charge need to encapsulate a Free Sql? Itself net core provides IHost and AppConfig services. Why does the person in charge need to encapsulate another layer to form a nuget package?

About point 2: (if the user finds that he is using Freesql now, in case of poor performance, and the caller wants to change it, how can I ask the caller to specify the new ORM framework he wants? That is, the caller doesn't want to use FreeSql)

The framework I wrote is actually based on the nuget package encapsulated by the person in charge's Freesql. In other words, I am a middleman. If this problem is established, shouldn't it be handled by the bottom, that is, the person in charge? What's more, there is a fatal mistake in the design idea. The person in charge wants the user to decide what Orm framework to use. Is this something that the person in charge should care about? The person in charge's reason is that if Freesql finds a performance problem, it needs to be replaced. What if the caller asks for a change? The general meaning of what I said to the person in charge yesterday is similar to that now, that is, this underlying implementation should not be interfered by the caller. For example, I called the EF framework. I can tell Microsoft that there is a performance problem with your current framework accessing the database. I ask Microsoft to change it to SqlSugar and Dapper immediately. Can the caller decide?

About the third point: (I open CodeFirst of FreeSql for user applications, which is highly coupled. In case other ones are not FreeSql, will you still have the exclusive object of CodeFirst?)

This is a good question, but since I am a middleman, I called the nuget package based on FreeSql written by the person in charge. Shouldn't this problem be implemented at the bottom, that is, in the nuget package of the person in charge? Of course, I can handle it here, but the design idea is actually bad. I didn't turn around yesterday. Since the question I was responsible for asking was a good question from the perspective of packaging, I agree with him. This is my problem. But in fact, this problem should be transmitted to the bottom processing. Not me as a middleman. Of course, I can handle it.

About point 4: (I encapsulate this. For multiple databases, multiple IRepository objects will be generated. Now I encapsulate only for the case where there is only one IRepository. How to solve it if multiple databases are used?)

This is indeed a good problem, because this problem exists objectively. But similarly, the person in charge asked me this question. Shouldn't this problem be handled and implemented by the bottom? Yesterday, the person in charge replied that he is only used for CIM, and the project has only one database, so there is no problem. But the project I'm doing now is to make it universal, so we should consider this problem. So, this is my problem. When I heard this yesterday, my brain didn't react, so I admitted that it was my own problem.

Feel and watch, welcome to correct.

Keywords: C# Back-end OOP

Added by dirtyfrenchman on Wed, 15 Dec 2021 13:06:38 +0200