在 C# 中访问数据库的最佳方法(设计模式)是什么?

And*_*yle 2 c# database design-patterns visual-studio

我是设计模式的新手。目前我正在开发一个系统,我有一个关系数据库。从我的数据库进行 CRUD 的最佳方法是什么?我当前的代码如下所示(C# 代码):

我为所有类定义了一个带有公共函数的接口。

namespace Model
{
    public interface ICommon
    {
        void insert();
        void update();
        void delete();
    }
}
Run Code Online (Sandbox Code Playgroud)

Common 类(抽象类)实现了 ICommon 接口和一些命令方法和属性。

namespace Model
{
    public abstract class Common : ICommon
    {
        public Guid RecId { set; get; }

        public abstract void insert();
        public abstract void update();
        public abstract void delete();
        public abstract List<Common> find();

        /// <summary>
        /// Insert or update the record
        /// </summary>
        public void save()
        {
            if (this.RecId == Guid.Empty)
            {
                this.insert();
            }
            else
            {
                this.update();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,适当的类(例如 UserTable 类)扩展 Common 类并实现抽象方法和其他特定属性。

我从 StoresProcedures 和 SqlParameter、SqlCommand 和 SqlConnection 执行 CRUD 的方式。这是一个例子:

    class CustTableModel : Common
        {
            public string SerialNumber { set; get; }
            public string ApplicationVersion { set; get; }
            public string KernelVersion { set; get; }
            public string Name { set; get; }
            public bool Active { set; get; }

            public override void insert()
            {
                List<SqlParameter> parameters = new List<SqlParameter>();
                SqlParameter parameter;

                // SerialNumber
                parameter = new SqlParameter("@serialNumber", System.Data.SqlDbType.Int);
                parameter.Value = this.SerialNumber;
                parameters.Add(parameter);

                // ApplicationVersion
                parameter = new SqlParameter("@applicationVersion", System.Data.SqlDbType.Int);
                parameter.Value = this.ApplicationVersion;
                parameters.Add(parameter);

                // KernelVersion
                parameter = new SqlParameter("@kernelVersion", System.Data.SqlDbType.Int);
                parameter.Value = this.KernelVersion;
                parameters.Add(parameter);

                // Name
                parameter = new SqlParameter("@name", System.Data.SqlDbType.Int);
                parameter.Value = this.Name;
                parameters.Add(parameter);

                // Active
                parameter = new SqlParameter("@active", System.Data.SqlDbType.Bit);
                parameter.Value = this.Active;
                parameters.Add(parameter);

                DBConn.execute("CUSTTABLE_INSERT", parameters); // The code of DBConn is below.
}
}
Run Code Online (Sandbox Code Playgroud)

为了更好地理解,这里是 DBConn 类:

public class DBConn
    {
        protected SqlConnection sqlConnection;
        protected string command { set; get; }
        protected List<SqlParameter> parameters { set; get; }

        protected void openConnection()
        {
            this.sqlConnection = new SqlConnection();
            this.sqlConnection.ConnectionString = "Data Source=.\\SQLEXPRESS;Initial Catalog=JYL_SOAWS_DB;Integrated Security=True";
            this.sqlConnection.Open();
        }

        protected void closeConnection()
        {
            if (this.sqlConnection.State == System.Data.ConnectionState.Open)
            {
                this.sqlConnection.Close();
            }
        }

        /// <summary>
        /// Executa o processo no banco.
        /// </summary>
        /// <returns>Quantidade de registros afetados.</returns>
        protected SqlDataReader run()
        {
            SqlCommand command = new SqlCommand();
            SqlDataReader ret;

            this.openConnection();

            command.CommandType = System.Data.CommandType.StoredProcedure;
            command.Connection = this.sqlConnection;
            command.CommandText = this.command;

            if (this.parameters != null)
            {
                foreach (SqlParameter parameter in this.parameters)
                {
                    command.Parameters.Add(parameter);
                }
            }

            ret = command.ExecuteReader();

            this.closeConnection();

            return ret;
        }

        /// <summary>
        /// Interface da classe à outros objetos.
        /// </summary>
        /// <param name="commandName">Nome da store procedure a ser executada.</param>
        /// <param name="parameters">A lista com os parâmetros e valores.</param>
        /// <returns>Numero de registros afetados.</returns>
        public static SqlDataReader execute(string commandName, List<SqlParameter> parameters = null)
        {
            DBConn conn = new DBConn();

            conn.command = commandName;
            conn.parameters = parameters;

            return conn.run();
        }
    }
Run Code Online (Sandbox Code Playgroud)

我很确定有更好的方法。

有人可以帮助我吗?谢谢是提前。

Jon*_*tes 5

您在这里发现了两种微妙不同的模式。

第一个是存储库模式- 一种从数据访问中抽象出业务逻辑的方法

第二种是Active Record模式,实体负责在数据库中维护自己的状态。

我建议你远离 C# 中的 ActiveRecord(你现在可能知道也可能不知道控制反转模式,但它非常有用并且与 AR 相当不兼容)。

如果你开始,我建议你看看像dapper.net这样的东西(我仍然在我的小项目中使用它)。它是一个 Micro-ORM,它从使用数据库中去除了很多样板,没有自以为是或难以学习(我使用并喜欢 EntityFramework 和 NHibernate,但对于初学者来说,它们并不容易上手)。

与此同时,我将创建一个存储库(一个具有 Create(Foo entity)、Read(Guid entityId)、Update(Foo entity) 和 Delete(Guid entityId) 方法的类)。

顺便说一句,使用 Guid 作为主键时要小心,因为它们会导致一个有趣的情况:由于大多数 Guid 实现(几乎总是)具有非顺序布局,并且数据按主键物理排序,这样的插入可以当数据库重新排序磁盘上的数据页以容纳插入到表中任意位置的新数据时,会导致大量磁盘 IO。用作主键的 Guid 生成的一个好策略是使用Guid Comb生成器

祝你好运!