我知道之前已经问过这些问题,我将首先列出其中一些问题(我到目前为止已经阅读过的):
正如你所看到的那样,关于这个主题的SO本身有一些很好的资源,但是有一个问题/部分的问题,我仍然不确定是否已经阅读了这些内容.
我主要关注IEnumerable和IQueryable问题,更具体地说是DAL与它的消费者之间的耦合.
我发现有关两个接口的建议各不相同,这两个接口都很棒.但是,我关注的是DAL返回IQueryable的含义.据我了解,IQueryable建议/暗示有一个Linq提供商.这是第一个问题 - 如果DAL突然需要来自非Linq提供的数据源,该怎么办?以下方法可行,但它更像是黑客攻击吗?
public static IQueryable<Product> GetAll()
{
// this function used to use a L2S context or similar to return data
// from a database, however, now it uses a non linq provider
// simulate the non linq provider...
List<Product> results = new …Run Code Online (Sandbox Code Playgroud) 索引器的扩展方法,它们会好吗?
我正在玩一些重新补充POCO的代码.
代码迭代从SqlDataReader返回的行,并使用反射从列值分配属性.在我的调用堆栈中,我有一个像这样的代码: -
poco.Set("Surname", "Smith"); // uses extension method ...
Run Code Online (Sandbox Code Playgroud)
Set方法被编写为扩展方法.
能够编写这样的代码会很棒
poco["Surname"] = "Smith"; // extension methods for indexers ?
Run Code Online (Sandbox Code Playgroud)
即我想为索引器编写扩展方法
有没有充分的理由说.Net没有索引器的扩展方法?其他人对扩展方法索引器有其他好的用途吗?
如果我们可以为索引器编写扩展方法,那么我们可以编写这样的代码......
var poco = PocoFactory();
poco.Surname = “Smith”; // is this JavaScript ...
poco[Surname] = “Smith” ; // … or is this c# or both
Run Code Online (Sandbox Code Playgroud)
我的代码中的一些片段
/////////////////////////////////////////////
// Client calling code
IDab dab = DabFactory.Create( "Northwind" );
string sql = @"select * from Customers ";
var persons = dab.ExecuteReader<NorthwindCustomer>(sql);
if (dab != null{
Assert.That(persons[0].CustomerID , Is.EqualTo("ALFKI"));} …Run Code Online (Sandbox Code Playgroud) 我正在研究POCO和DTO之间的差异(似乎POCO与行为有关(方法?))并且Martin Fowler在贫血领域模型上发现了这篇文章.
由于缺乏理解,我认为我已经创建了这些贫血领域模型之一.
在我的一个应用程序中,我将业务域实体定义为'dto'dll.他们有很多属性,包括getter和setter,而不是其他.我的业务逻辑代码(填充,计算)位于另一个"bll"dll中,我的数据访问代码位于"dal"dll中.我认为'最佳实践'.
所以通常我会像这样创建一个dto:
dto.BusinessObject bo = new dto.BusinessObject(...)
Run Code Online (Sandbox Code Playgroud)
并将其传递给bll层,如下所示:
bll.BusinessObject.Populate(bo);
Run Code Online (Sandbox Code Playgroud)
反过来,它执行一些逻辑并将其传递给dal层,如下所示:
dal.BusinessObject.Populate(bo);
Run Code Online (Sandbox Code Playgroud)
根据我的理解,为了使我的dto成为POCO,我需要将业务逻辑和行为(方法)作为对象的一部分.所以代替上面的代码更像是:
poco.BusinessObject bo = new poco.BusinessObject(...)
bo.Populate();
Run Code Online (Sandbox Code Playgroud)
即.我在对象上调用方法而不是将对象传递给方法.
我的问题是 - 我怎么能这样做,仍然保留关注点的'最佳实践'层次(单独的dll等...).不调用对象上的方法意味着必须在对象中定义方法?
请帮助我的困惑.
实际上更好的是什么?让具有复杂查询的类负责加载实例嵌套对象?或者带有简单查询的类负责加载简单对象?
对于复杂的查询,您必须减少对数据库的影响,但课程将承担更多责任.
或简单查询,您需要更多地访问数据库.在这种情况下,每个类将负责加载一种类型的对象.
我所处的情况是加载的对象将被发送到Flex应用程序(DTO).
因此,我们就工作中的DataAccess路径进行了激烈的争论:DataTable或DataReader.
免责声明我在DataReader方面,这些结果震撼了我的世界.
我们最终编写了一些基准来测试速度差异.人们普遍认为DataReader速度更快,但我们想看看速度有多快.
结果让我们感到惊讶.DataTable始终比DataReader更快.有时接近两倍的速度.
所以我转向你,SO的成员.为什么,当大多数文档甚至微软声称DataReader更快时,我们的测试显示不然.
现在代码:
测试工具:
private void button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
DateTime date = DateTime.Parse("01/01/1900");
for (int i = 1; i < 1000; i++)
{
using (DataTable aDataTable = ArtifactBusinessModel.BusinessLogic.ArtifactBL.RetrieveDTModified(date))
{
}
}
sw.Stop();
long dataTableTotalSeconds = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 1; i < 1000; i++)
{
List<ArtifactBusinessModel.Entities.ArtifactString> aList = ArtifactBusinessModel.BusinessLogic.ArtifactBL.RetrieveModified(date);
}
sw.Stop();
long listTotalSeconds = sw.ElapsedMilliseconds;
MessageBox.Show(String.Format("list:{0}, table:{1}", listTotalSeconds, dataTableTotalSeconds));
}
Run Code Online (Sandbox Code Playgroud)
这是DataReader的DAL:
internal static List<ArtifactString> RetrieveByModifiedDate(DateTime modifiedLast) …Run Code Online (Sandbox Code Playgroud) 我来自一个有利于构建自己的世界而不是依赖其他人构建的库和框架.在逃离这个世界之后,我发现在Visual Studio中使用Typed DataSet等工具的快乐和轻松.除了失去灵活性,你还会失去什么?是否有性能因素(无视procs与动态sql争论)?限制?
我对感知"最佳实践"感兴趣,在这里用一点点现实来锻炼.
在Web应用程序中,您是否允许您的Web层直接访问DAL,还是应该首先通过BLL?
我特别谈的是没有真正涉及"业务逻辑"的场景 - 比如一个简单的查询:"获取姓氏为'Atwood'的所有客户".那些有任何逻辑的场景绝对会通过BLL,所以我们称之为moo.
虽然您可以将此方法封装在BLL对象中,但是当签名与DLL对象的签名完全相同时,似乎有点无意义,并且代码可能与将查询委派给DLL的一个简单的代码一样简单.
如果选择前者 - 使用BLL对象 - 你称这些对象是什么?(假设它们只是在DLL中提供查询层).助手?QueryProviders?
想一想.
问候
马蒂
我一直试图寻找一种有效的方法来在C#中对我的数据访问层进行单元测试.我是主要的Java开发人员,并且只使用了C#大约6个月,过去我使用了一个名为DBUnit的库来测试已知的状态数据库.我一直无法找到一个可以使用的类似活动库,最近似乎是nDBUnit,但它现在已经有一段时间没有活动了.
关于C#中的方式和原因似乎存在很多相互矛盾的方法.理想情况下,我想使用模拟测试数据访问层,而无需连接到数据库,然后在一组单独的测试中对存储过程进行单元测试.
在我正在研究的系统中,数据访问层是使用ADO.net(不使用实体框架)来调用SQL Server上的存储过程.
下面是我必须使用的示例代码; 沿着模拟路径走下去,我必须能够模拟SqlCommand(使用IDbCommand)和/或模拟SqlConnection.
所以我的问题是什么似乎是最好的方式(如果有这样的事情)这样做?到目前为止,唯一的方法是使代理对象传递给构造函数,以便它可以返回模拟的Sql*对象进行测试.
我还没有机会查看所有可用的C#模拟库.
public class CustomerRepository : ICustomerRepository
{
private string connectionString;
public CustomerRepository (string connectionString)
{
this.connectionString = connectionString;
}
public int Create(Customer customer)
{
SqlParameter paramOutId = new SqlParameter("@out_id", SqlDbType.Int);
paramOutId.Direction = ParameterDirection.Output;
List<SqlParameter> sqlParams = new List<SqlParameter>()
{
paramOutId,
new SqlParameter("@name", customer.Name)
}
SqlConnection connection = GetConnection();
try
{
SqlCommand command = new SqlCommand("store_proc_name", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(sqlParams.ToArray());
int results = command.ExecuteNonQuery();
return (int) paramOutId.Value;
}
finally
{
CloseConnection(connection);
}
} …Run Code Online (Sandbox Code Playgroud) 我已经在几个Web应用程序中实现了我认为相当不错的MVC表示,但是自从加入了crackoverflow之后,我发现也许我的初始定义有点简单,因此我真的想要澄清一下它们之间的区别.数据访问层和Web应用程序的模型或域层.
对于上下文,我目前使用数据访问对象为对象表示的表中的单个记录实现CRUD函数,以及get()函数返回一个允许我遍历所有满足get()函数的标准.
这些数据访问对象直接从包含我的业务逻辑的控制器脚本引用.
如果它很重要,我正在使用PHP和MySQL,但我对可能用其他语言编码的建议感兴趣.
更新:对于一个更具体的例子,我有一个名为user的表(这里的约定是单个表名),它包含诸如电子邮件地址,活动状态,用户名,密码,它们所属的公司等信息.这个基本对象会在代码中看起来像这样:
class User implements DataAccessObject
{
protected $user_id;
protected $email;
protected $username;
protected $password;
protected $company_id;
protected $active // Bool that holds either a 0 or 1
public function __construct ( $user_id ) // Uses Primary Key to know which record to construct
{
$sql = //Sql to get this information from the database.
// Code necessary to assign member variables their values from the query.
}
public function insert(){}
public function update(){}
public function …Run Code Online (Sandbox Code Playgroud) 我正试图找出最干净的方法来做到这一点.
目前我有一个客户对象:
public class Customer
{
public int Id {get;set;}
public string name {get;set;}
public List<Email> emailCollection {get;set}
public Customer(int id)
{
this.emailCollection = getEmails(id);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我的Email对象也很基本.
public class Email
{
private int index;
public string emailAddress{get;set;}
public int emailType{get;set;}
public Email(...){...}
public static List<Email> getEmails(int id)
{
return DataAccessLayer.getCustomerEmailsByID(id);
}
}
Run Code Online (Sandbox Code Playgroud)
DataAccessLayer当前连接到数据库,并使用SqlDataReader迭代结果集并创建新的Email对象,并将它们添加到完成时返回的List.
那么我在哪里以及如何改进呢?
我是否应该让我的DataAccessLayer返回一个DataTable并将其留给Email对象进行解析并将List返回给Customer?
我猜"工厂"可能是错误的单词,但是我应该有另一种类型的EmailFactory从DataAccessLayer获取DataTable并将List返回给Email对象吗?我想这种声音多余......
将我的Email.getEmails(id)作为静态方法,这是否是正确的做法?
我可能只是试图找到并应用最好的"模式"来完成一项简单的任务.
谢谢.
跟进
我创建了一个工作示例,其中我的域/业务对象通过现有数据库中的id提取客户记录.nhibernate中的xml映射文件非常简洁.在我按照教程设置会话和存储库工厂之后,拉动数据库记录非常简单.
但是,我注意到了巨大的性能损失.
我的原始方法由DB上的存储过程组成,该过程由DAL对象调用,该对象将结果集解析为我的域/业务对象.
我用30分钟的原始方法来获取单个客户记录.然后我用nhibernate方法计时3000ms来获取相同的记录.
我错过了什么吗?或者使用这种nhibernate路由会有很多开销吗?
否则我喜欢代码的清洁度:
protected void Page_Load(object sender, EventArgs e)
{
ICustomerRepository repository = new CustomerRepository();
Customer …Run Code Online (Sandbox Code Playgroud)