1

问题

我有一些代码,我以这种方式编写了代码,以实现高可维护性和代码可重用性。我担心一段特定的代码,我想就这段代码是否会在高压力下崩溃提出专业意见。

Codez ##

public abstract class PlexxisDataTransferObjects : PlexxisDatabaseRow
    {
        //static methods
        public static List<PlexxisDatabaseRow> GetAll();

        //Constructors
        public PlexxisDataTransferObjects(){ }

        //Methods
        public abstract bool Insert(OracleConnection Conn);
        public abstract bool Update(OracleConnection Conn);
        public abstract bool Delete(OracleConnection Conn);

        public bool Insert()
        {
            using (var Conn = new OracleConnection(ConnectionString))
            {
                Conn.Open();
                return Insert(Conn);
            }
        }
        public bool Update()
        {
            using (var Conn = new OracleConnection(ConnectionString))
            {
                Conn.Open();
                return Update(Conn);
            }
        }
        public  bool Delete()
        {
            using (var Conn = new OracleConnection(ConnectionString))
            {
                Conn.Open();
                return Delete(Conn);
            }
        }
    }


    //Data Transfer Objects
    public sealed class Apps : PlexxisDataTransferObjects
    {
        //Static Methods
        public override static List<PlexxisDatabaseRow> GetAll()
        {
            List<PlexxisDatabaseRow> collection = new List<PlexxisDatabaseRow>();
            using (var Conn = new OracleConnection(ConnectionString))
            {
                using (var Command = new OracleCommand("select * from APPS", Conn))
                {
                    Conn.Open();
                    using (var reader = Command.ExecuteReader(CommandBehavior.CloseConnection))
                        while (reader.Read())
                            collection.Add(new Apps(reader));
                }
            }
            return collection;
        }

        //Fields
        public int AppId;
        public string AuthKey;
        public string Title;
        public string Description;
        public bool isClientCustomApp;

        //Constructors
        public Apps() : base () { }
        public Apps(OracleDataReader reader) : base ()
        {
            if (reader["APP_ID"] != DBNull.Value)
                this.AppId = Convert.ToInt32(reader["APP_ID"]);

            if (reader["AUTH_KEY"] != DBNull.Value)
                this.AuthKey = Convert.ToString(reader["AUTH_KEY"]);

            if (reader["TITLE"] != DBNull.Value)
                this.Title = Convert.ToString(reader["TITLE"]);

            if (reader["DESCRIPTION"] != DBNull.Value)
                this.Description = Convert.ToString(reader["DESCRIPTION"]);

            if (reader["IS_CLIENT_CUSTOM_APP"] != DBNull.Value)
                this.isClientCustomApp = Convert.ToBoolean(reader["IS_CLIENT_CUSTOM_APP"]);
        }

        //Methods
        public override bool Insert(OracleConnection Conn)
        {

            string sql = string.Empty;
            sql += "INSERT INTO APPS (APP_ID, AUTH_KEY, TITLE, DESCRIPTION, IS_CLIENT_CUSTOM_APP)";
            sql += "VALUES(:appid, :authkey, :title, :description, :iscust)";

            using (var Command = new OracleCommand(sql, Conn))
            {
                AppId = GetId();
                Command.Parameters.Add(":appid", OracleDbType.Int32).Value = AppId;
                Command.Parameters.Add(":authkey", OracleDbType.Varchar2).Value = AuthKey;
                Command.Parameters.Add(":title", OracleDbType.Varchar2).Value = Title;
                Command.Parameters.Add(":description", OracleDbType.Varchar2).Value = Description;
                Command.Parameters.Add(":iscust", OracleDbType.Int32).Value = Convert.ToInt32(isClientCustomApp);

                return Convert.ToBoolean(Command.ExecuteNonQuery());
            }
        }
        public override bool Update(OracleConnection Conn)
        {
            string sql = string.Empty;
            sql += "UPDATE APPS SET ";
            sql += "AUTH_KEY = :authkey, TITLE = :title, DESCRIPTION = :description, IS_CLIENT_CUSTOM_APP = :iscust ";
            sql += "WHERE APP_ID = :appid";

            using (var Command = new OracleCommand(sql, Conn))
            {
                Command.Parameters.Add(":authkey", OracleDbType.Varchar2).Value = AuthKey;
                Command.Parameters.Add(":title", OracleDbType.Varchar2).Value = Title;
                Command.Parameters.Add(":description", OracleDbType.Varchar2).Value = Description;
                Command.Parameters.Add(":iscust", OracleDbType.Int32).Value = Convert.ToInt32(isClientCustomApp);
                Command.Parameters.Add(":appid", OracleDbType.Int32).Value = AppId;

                return Convert.ToBoolean(Command.ExecuteNonQuery());
            }
        }
        public override bool Delete(OracleConnection Conn)
        {
            string sql = string.Empty;
            sql += "DELETE FROM APPS ";
            sql += "WHERE APP_ID = :appid";

            using (var Command = new OracleCommand(sql, Conn))
            {
                Command.Parameters.Add(":appid", OracleDbType.Int32).Value = AppId;
                return Convert.ToBoolean(Command.ExecuteNonQuery());
            }
        }
    }

我在看什么?

我最关心的是抽象类中的Insert、Update 和Delete 方法调用具体类中的Insert、Update 和Delete。

我这样做是为了在必要时通过打开连接并显式启动事务、发送事务并仍然让对象做他们需要做的事情来启用事务;此外,如果我必须为 40 个左右的类显式地重写这 3 个方法,它可能会变得非常麻烦。

但是,我担心过早打开连接可能会占用数据库。我不知道在任何给定时间可能会更新多少输入数据。在这种情况下,我有两个主要想法,我可以在抽象类中进行插入、更新和删除抽象,并在紧接在 Command.ExecuteNonQuery() 之前显式打开连接时实现它们,或者我可以保留它现在的样子。

我想从你那里得到什么?

首先,你对情况的看法。其次,指出逻辑背后的任何陷阱或您碰巧发现的任何错误编码也将非常有帮助。

4

2 回答 2

3

我认为这可能值得研究工作单元模式。

在我看来,您似乎已经在使用活动记录模式,但是我发现您的类定义被硬编码为依赖于 oracle 是有问题的(从关注点和依赖项的角度来看),这意味着代码使用你的 DTO 也必须依赖于 oracle。如果您想切换数据库,我并不是说这是一个问题,我是说最好的做法是拥有一个非常解耦的系统,以便理解和单元测试。

数据库无关代码

class Application
{
    public int ID { get; set; }
    public string AuthKey { get; set; }
    // and so on
}

interface IApplicationRepository
{
    IEnumerable<Application> GetAll();
    void Update(Application app);
    void Delete(Application app);
    void Insert(Application app);
}

interface IUnitOfWork : IDisposable
{
    IApplicationRepository Applications { get; }
    void Commit();
}

消费代码

void SaveButton_Click(object sender, EventArgs e)
{
    // this could be resolved by dependency injection, this would know about Oracle
    using (var uow = UnitOfWorkFactory.Create()) 
    {
        uow.Applications.Insert(new Application { AuthKey = "1234" });

        // you may have other repo that have work done in the same transaction / connection

        uow.Commit();
    }
}

如果您查看上面编写的所有代码,则没有提及 Oracle,甚至没有提及连接或事务的概念。你有这个抽象UnitOfWork,它在幕后管理你的应用程序的状态。存储库与普通类一起使用。这种类型的代码很容易模拟和编写测试。这对于可维护性来说是巨大的。

数据库特定代码

class OracleApplicationRepository : IApplicationRepository
{
    public readonly OracleDbConnection _dbConnection;

    public OracleApplicationRepository(OracleDbConnection dbConnection)
    {
        _dbConnection = dbConnection;
    }

    IEnumerable<Application> GetAll()
    {
        // up to you, the viewer
        throw new NotImplementedException();
    }

    void Update(Application app)
    {
        // up to the viewer
    }

    void Delete(Application app)
    {
        // up to the viewer
    }

    void Insert(Application app)
    {       
        using (var command = _dbConnection.CreateCommand())
        {
            // or whatever the syntax is
            command.Parameters["AuthKey"] = app.AuthKey;

            command.ExecuteNonQuery();
        }
    }
}

class OracleUnitOfWork : IUnitOfWork
{
    private readonly OracleDbConnection _dbConnection;

    public OracleUnitOfWork(string connectionString)
    {
        _dbConnection = new OracleDbConnection(connectionString);
    }

    public IApplicationRepository Applications 
    {
        get
        {
            // this could be lazy loaded instead of making new instances all over the place
            return new OracleApplicationRepository(_dbConnection); 
        }
    }

    public Dispose()
    {
        // close the connection and any transactions
        _dbConnection.Dispose();
    }
}
于 2013-09-10T18:51:30.323 回答
0

如果您正在循环大量数据,则为每个 CRUD 操作打开和关闭数据库连接会受到影响。此外,您应该使用 try、catch 和 finally。您不能保证数据库会启动并且会引发异常。

于 2013-09-10T18:48:45.937 回答