MS Access、命名参数和列名称
我正在 Access 数据库上执行以下查询。在 Access 中运行时,查询会返回准确的结果。但是,当从代码运行时,我会取回数据库中的所有项目,甚至是那些超出我正在搜索的日期范围的项目。
我想知道问题是否是因为参数名称与表中的列名称相同,因此我将参数名称 @StartDate
和 @EndDate
更改为 < code>@FromDate 和 @ToDate
这解决了问题,如果参数名称不同,我会得到正确的结果集。这让我担心,因为在我正在研究的项目中,这种模式到处都是重复的。但是,我使用名为 @Id
的参数通过 Id
(数据库表中的列名称)更新记录,并且工作正常。这是一个奇怪的边缘情况吗?任何人都可以阐明这种行为吗?
对大量代码示例表示歉意,但在这种情况下,我认为需要整个方法。
public override AcademicCycleTransportCollection FetchForDateRange(DateTime startDate, DateTime endDate) {
const String query =
"PARAMETERS \n" +
" @StartDate DATE, \n" +
" @EndDate DATE \n" +
" ; \n" +
"SELECT \n" +
" [AcademicCycle].[Id] AS [Id], \n " +
" [AcademicCycle].[Name] AS [Name], \n " +
" [AcademicCycle].[AcademicCycleCategoryId] AS [AcademicCycleCategoryId], \n " +
" [AcademicCycle].[ParentAcademicCycleId] AS [ParentAcademicCycleId], \n " +
" [AcademicCycle].[StartDate] AS [StartDate], \n " +
" [AcademicCycle].[EndDate] AS [EndDate], \n " +
" [AcademicCycle].[IsPerpetual] AS [IsPerpetual], \n " +
" [AcademicCycle].[IsLocked] AS [IsLocked] \n " +
"FROM \n" +
" AcademicCycle \n" +
"WHERE \n" +
" (StartDate <= @EndDate AND EndDate >= @StartDate) OR \n" +
" IsPerpetual <> 0";
AcademicCycleTransportCollection transportCollection = new AcademicCycleTransportCollection();
OleDbCommand _fetchForDateRangeCommand = null;
if (_fetchForDateRangeCommand == null) {
OleDbConnection connection = _parentDataConnection.Connection;
_fetchForDateRangeCommand = new OleDbCommand(query, connection);
_fetchForDateRangeCommand.Parameters.Add("@StartDate", OleDbType.Date);
_fetchForDateRangeCommand.Parameters.Add("@EndDate", OleDbType.Date);
}
_fetchForDateRangeCommand.Transaction = _parentDataConnection.Transaction;
_fetchForDateRangeCommand.Parameters["@StartDate"].Value = startDate;
_fetchForDateRangeCommand.Parameters["@EndDate"].Value = endDate;
using (OleDbDataReader dbReader = _fetchForDateRangeCommand.ExecuteReader()) {
NullableDataReader reader = new NullableDataReader(dbReader);
while (reader.Read()) {
AcademicCycleTransport transport = FillTransport(reader);
transportCollection.Add(transport);
}
if (!reader.IsClosed) {
reader.Close();
}
}
return transportCollection;
}
I have the following query which I am executing on an Access database. The query, when run in Access returns accurate results. However when run from the code I get back all of the items in the database, even those which fall outside the date range I am searching for.
I was wondering if the issue was because the parameter names are the same as the column names in the table, so I changed the parameter names @StartDate
and @EndDate
to be @FromDate
and @ToDate
and this fixed the problem, if the parameter names are different I get the right result set back. This concerns me because in the project that I am working on this pattern is duplicated all over the place. However I am using a parameter named @Id
to update the records by Id
(column name in db table) and this is working fine. Is this a weird edge case? Can anyone shed any light on this behaviour.
Apologies for the massive code sample, but in this case I think the whole method is needed.
public override AcademicCycleTransportCollection FetchForDateRange(DateTime startDate, DateTime endDate) {
const String query =
"PARAMETERS \n" +
" @StartDate DATE, \n" +
" @EndDate DATE \n" +
" ; \n" +
"SELECT \n" +
" [AcademicCycle].[Id] AS [Id], \n " +
" [AcademicCycle].[Name] AS [Name], \n " +
" [AcademicCycle].[AcademicCycleCategoryId] AS [AcademicCycleCategoryId], \n " +
" [AcademicCycle].[ParentAcademicCycleId] AS [ParentAcademicCycleId], \n " +
" [AcademicCycle].[StartDate] AS [StartDate], \n " +
" [AcademicCycle].[EndDate] AS [EndDate], \n " +
" [AcademicCycle].[IsPerpetual] AS [IsPerpetual], \n " +
" [AcademicCycle].[IsLocked] AS [IsLocked] \n " +
"FROM \n" +
" AcademicCycle \n" +
"WHERE \n" +
" (StartDate <= @EndDate AND EndDate >= @StartDate) OR \n" +
" IsPerpetual <> 0";
AcademicCycleTransportCollection transportCollection = new AcademicCycleTransportCollection();
OleDbCommand _fetchForDateRangeCommand = null;
if (_fetchForDateRangeCommand == null) {
OleDbConnection connection = _parentDataConnection.Connection;
_fetchForDateRangeCommand = new OleDbCommand(query, connection);
_fetchForDateRangeCommand.Parameters.Add("@StartDate", OleDbType.Date);
_fetchForDateRangeCommand.Parameters.Add("@EndDate", OleDbType.Date);
}
_fetchForDateRangeCommand.Transaction = _parentDataConnection.Transaction;
_fetchForDateRangeCommand.Parameters["@StartDate"].Value = startDate;
_fetchForDateRangeCommand.Parameters["@EndDate"].Value = endDate;
using (OleDbDataReader dbReader = _fetchForDateRangeCommand.ExecuteReader()) {
NullableDataReader reader = new NullableDataReader(dbReader);
while (reader.Read()) {
AcademicCycleTransport transport = FillTransport(reader);
transportCollection.Add(transport);
}
if (!reader.IsClosed) {
reader.Close();
}
}
return transportCollection;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
按照您的方式,OleDb 使用位置参数插入,因此 SQL 中的第一个参数“@EndDate”将被传递的第一个参数“@StartDate”替换。使用位置插入时,参数的名称将被完全忽略。
然而,鲜为人知的事实是 OleDb 实际上接受命名参数。您还必须在 SQL 中声明参数。
请参阅:low-bandwidth.blogspot.com。 au/2013/12/positional-msaccess-oledb-parameters.html
如果您不在 SQL 中声明参数,OleDb 使用纯粹的位置参数插入,并且参数名称是否匹配并不重要SQL,或者如果参数在 SQL 中使用了两次 - 它只会从开始到结束的顺序遍历并盲目替换 SQL 中找到的任何参数,以及传递的参数。
但是,如果正确声明参数,您将受益于命名参数和允许在 SQL 语句中重复多次的参数。
The way you have done it, OleDb is using positional parameter insertion, so your first parameter in SQL, '@EndDate' is being substituted with the first parameter passed, '@StartDate'. The names of the parameters are completely ignored when using positional insertion.
However, it's a little-known fact that OleDb actually DOES accept named parameters. You've just got to declare the parameters in SQL as well.
See: low-bandwidth.blogspot.com.au/2013/12/positional-msaccess-oledb-parameters.html
If you DON'T declare the parameters in SQL, OleDb uses purely positional parameter insertion, and it doesn't matter if the names of the parameters match the SQL, or if parameters are used twice in the SQL - it will just go through and blindly replace any found parameters in the SQL in order from start to end, with those passed.
However if you DO declare the parameters correctly, you get the benefit of named parameters and parameters allowed to be repeated multiple times within the SQL statement.
尝试使用所需的参数直接编辑查询字符串。简单示例(输出查询字符串):
“SELECT t001_clients.cli_id as id, t001_clients.cli_name WHERE (id = 1);”
这不是最漂亮的方式,但会起作用。请注意参数上的类型字符(“cli_name = 'John Smith'”或“cli_birthday = #12/27/1980#”)
另外,为什么不使用 linq 查询?应该更容易...
try to edit the query string directly with the desired parameters. Simple example (output query string):
"SELECT t001_clients.cli_id as id, t001_clients.cli_name WHERE (id = 1);"
Isn't the pretiest way but would work. Be care about the type characters on parameters ("cli_name = 'John Smith'" or "cli_birthday = #12/27/1980#")
Also, why did not you use linq queryes? Should be easier...