我是设计模式的新手。 目前我正在开发一个系统,我有一个版权DB。从我的数据库到CRUD的最佳方法是什么? 我当前的代码如下所示(C#代码):
我为所有类定义了一个带公共函数的接口。
namespace Model
{
public interface ICommon
{
void insert();
void update();
void delete();
}
}
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();
}
}
}
}
然后,正确的类(例如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.
}
}
为了更好地理解,这里是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();
}
}
我很确定有更好的方法。
有人能帮帮我吗?谢谢你的到来。
答案 0 :(得分:4)
你在这里遇到了两个微妙的不同模式。
第一个是repository pattern - 一种从数据访问中抽象出业务逻辑的方法
第二种是Active Record模式,即实体负责在数据库中维护自己的状态。
我建议你远离C#中的ActiveRecord(你现在可能知道或者可能不知道Inversion of Control模式,但它非常有用且与AR相当不兼容。)
如果你刚开始的话,我会建议你看看像dapper.net这样的东西(我仍然在我的小项目中使用它)。它是一个Micro-ORM,它使用大量的样板远离使用数据库,没有看法或难以学习(我使用和喜欢EntityFramework&amp; NHibernate,但它们并不容易为初学者选择)
与此同时,我将创建一个存储库(一个包含Create(Foo实体),Read(Guid entityId),Update(Foo实体)和删除(Guid entityId)方法的类)。
另外,在使用Guids作为主键时要小心,因为它们可能会导致一个有趣的情况:由于大多数Guid实现(几乎总是)具有非顺序布局,并且数据按主键进行物理排序,例如insert可能会导致大量磁盘IO,因为数据库会重新排序磁盘上的数据页,以适应插入表中某个任意位置的新数据。 Guid生成用作主键的一个好策略是使用Guid Comb生成器
祝你好运!
答案 1 :(得分:1)
这是最好的模式。我建议不要使用ORM。特别是EF
public class MyModel
{
public string Id {get;set;}
//public valuetype PropertyA {get;set;} //other properties
}
public interface IMyModelRepository
{
List<MyModel> GetModels();
MyModel GetModelById(string id);
void AddMyModel(MyModel model);
//other ways you want to get models etc
}
public class MyModelRepositorySql : IMyModelRepository
{
public List<MyModel> GetModels()
{
//SqlConnection etc etc
while (SqlDataReader.Read())
{
results.Add(this.populateModel(dr));
}
return results;
}
protected MyModel populateModel(SqlDataReader dr)
{
//map fields to datareader
}
public MyModel GetModelById(string id)
{
//sql conn etc
this.populateModel(dr);
}
}
这是我的理由。
使用存储库模式允许您注入持久化数据的方式,这些数据不需要数据库。这对于单元测试至关重要,但如果您可以将模拟存储库注入到项目中进行集成测试,您会发现它非常有用
ORM虽然起初看起来很容易,但从长远来看,节省很多打字会导致问题。你只需要搜索实体框架问题的堆栈溢出,就可以看到人们在遇到以次优方式运行的查询时遇到的结点。
在任何大型项目中,您将遇到数据获取要求,这需要一些优化的检索数据的方法,这将破坏您精心设计的对象图/可注入的通用存储库或聪明的前沿ORM
POCO对象很好。当您尝试将它们序列化或递归地添加到数据库等时,复杂对象(具有其他对象作为属性的对象)会很麻烦。保留基础数据模型POCO并仅使用linq将它们组合在服务或视图模型中。 / p>
使用GUID ID做得好btw!不要听那些认为永远不会用完的傻瓜! (存储为varchar(50)并让DBA对索引进行排序)任何数据库生成的id的问题是你必须能够在不连接数据库的情况下创建对象。
答案 2 :(得分:0)
对于执行CRUD操作,我建议使用Entity framework进行Repository模式。
实体框架是由Microsoft提供的ORM。它使用一组POCO类(实体)处理数据库,以执行插入/更新/删除/创建操作。
要对这些实体执行查询,将使用语言集成查询(LINQ)。 LINQ使用类似的SQL语法,它将数据库结果作为实体集合返回。
这是一个示例 Repository pattern with EF
干杯!