注意:您可能不需要阅读整个内容就知道出了什么问题...如果您愿意,可以跳到有关3个方案的部分。如果你想了解我如何尝试实现这一点以及错误发生的地方的背景信息,请阅读开头。
首先,我正在尝试检索存储在Clients
表中的CRM_Clients
列表,其中包含给定的callerId
。
我使用SelectLiveClientsForCaller
方法从Controller中检索客户端。然后,消息通过DataProvider类中的static Instance
方法传递给DAL:
public List<Client> SelectLiveClientsForCaller(int callerID)
{
List<Client> results = new List<Client>();
IDataReader reader;
reader = DataProvider.Instance().SelectLiveClientsForCaller(callerID);
if (reader.Read())
{
// If I break here and enumerate the reader, it says that the IEnumerable returned no results
results = CBO.FillCollection<Client>(reader); // Always comes out as a count of 0
}
return results;
}
我的DataProvider
类是一个抽象类,它概述了SqlDataProvider
可用的所有方法:
public abstract class DataProvider
{
// singleton reference to the instantiated object
static DataProvider objProvider = null;
// constructor
static DataProvider()
{
CreateProvider();
}
// dynamically create provider
private static void CreateProvider()
{
objProvider = (DataProvider)Reflection.CreateObject("data", "Owu.Modules.CRM", "");
}
// return the provider
public static DataProvider Instance()
{
return objProvider;
}
public abstract IDataReader SelectLiveClientsForCaller(int callerID);
/* More abstract methods here... */
}
在子类SqlDataProvider
中,实际处理了SelectLiveClientsForCaller
方法,并为存储过程SqlHelper.ExecuteReader
调用CRM_Clients_SelectLiveForCaller
:
public class SqlDataProvider : DataProvider
{
private const string ProviderType = "data";
private ProviderConfiguration _providerConfiguration = ProviderConfiguration.GetProviderConfiguration(ProviderType);
private string _myConnectionString;
private string _providerPath;
private string _objectQualifier;
private string _databaseOwner;
private string _moduleQualifier;
public SqlDataProvider()
{
//Read the configuration specific information for this provider
Provider objProvider = (Provider)_providerConfiguration.Providers[_providerConfiguration.DefaultProvider];
//Read the attributes for this provider
//Get Connection string from web.config
_myConnectionString = Config.GetConnectionString();
}
public string MyConnectionString
{
get { return _myConnectionString; }
}
public override IDataReader SelectLiveClientsForCaller(int callerID)
{
return (IDataReader)SqlHelper.ExecuteReader(
myConnectionString,
"CRM_Clients_SelectLiveForCaller",
callerID);
}
/* More methods here... */
}
最后,存储过程CRM_Clients_SelectLiveForCaller
ALTER PROCEDURE [dbo].[CRM_Clients_SelectLiveForCaller]
@CallerID int
AS
BEGIN
SET NOCOUNT ON;
IF @CallerID = -1
BEGIN
SELECT * FROM CRM_Clients WHERE IsDeleted = 'false'
END
ELSE
BEGIN
SELECT * FROM CRM_Clients WHERE ClientID IN
(SELECT ClientID FROM CRM_CallersClients WHERE CallerID = @CallerID)
AND IsDeleted = 'false'
END
END
返回给定callerid
的所有未删除客户端。
然后应该返回该行并返回控制器的结果......
到目前为止,我注意到了3种情况
如果没有从存储过程返回的记录(通过sql server mgmt studio执行),则在调用方法序列reader.Read()
时返回false并完全跳过它。
如果从存储过程返回1条记录(通过sql server mgmt studio执行),则在调用方法序列reader.Read()
时返回 true ,但枚举结果给出一条消息说 IEnumerable没有返回任何结果
如果从存储过程返回2条记录(通过sql server mgmt studio执行),则在调用方法序列reader.Read()
时,返回 true ,但枚举结果< strong>仅返回1条记录而不是2条
有人可以解释为什么我会为每种情况获得这些结果吗?
如果您需要更多信息,请询问,我会尽快更新。
谢谢,
马特
答案 0 :(得分:1)
每次调用reader.Read()都会读取一行,所以就像任何IEnumerable调用者使用行一样消耗行。
你需要重新考虑在填充例程之外调用.Read()以检查是否存在行,因为如果在使用当前位于阅读器中的行之前再次在填充例程中调用.Read(),则会丢失第一排。
答案 1 :(得分:0)
Reader.Read()仅检查返回的第一行,并自动将结果集移动到下一条记录。
请尝试以下方法:
while (reader.Read())
{
results = CBO.FillCollection<Client>(reader);
}
您可能需要调整FillCollection方法以适应此更改。
答案 2 :(得分:0)
reader.Read会告诉您记录是否可用
//expecting one record
if(reader.Read())
{
//get reader["values"];
}
或..
//expecting multiple records
while(reader.Read())
{
//get reader["values"];
}