EntityFramework Oracle 托管访问日期时间问题

EntityFramework with Oracle Managed Access DateTime issue

我有存储过程来根据输入参数执行搜索。

-- Search clients by specified input parameters.
create or replace procedure p_get_searchclients(i_iin             in  number default null,
                                            i_full_name       in  varchar default null,
                                            i_created_at_from in  timestamp default null,
                                            i_created_at_to   in  timestamp default null,
                                            result_cursor     out sys_refcursor) as
query_str varchar(200);
no_params_value exception;
begin
-- Check input parameters.
if i_iin is null and i_full_name is null and i_created_at_from is null and i_created_at_to is null
then
  raise no_params_value;
end if;

-- Base query string.
query_str := 'select * from t_client where 1=1 ';

-- Add search by IIN column to the query.
if i_iin is not null
then
  query_str := query_str || 'and iin like ''%' || i_iin || '%'' ';
end if;

-- Add search by FULL_NAME column to the query.
if i_full_name is not null
then
  query_str := query_str || 'and lower(full_name) like ''%' || lower(i_full_name) || '%'' ';
end if;

-- Add search range by the CREATED_AT column to the query.
if i_created_at_from is not null and i_created_at_to is not null
then
  query_str :=
  query_str || 'and created_at >= ' || i_created_at_from || ' and created_at <= ' || i_created_at_to || ' ';
elsif i_created_at_from is not null and i_created_at_to is null
  then
    query_str := query_str || 'and created_at >= ' || i_created_at_from || ' ';
elsif i_created_at_from is null and i_created_at_to is not null
  then
    query_str := query_str || 'and created_at <= ' || i_created_at_to;
end if;

-- Execute statement.
open result_cursor for query_str;

exception
when no_params_value
then
  raise_application_error(-20100, 'Необходимо указать как минимум один параметр для поиска.');
when others
then
  rollback;
end p_get_searchclients;

在我的应用程序中,我使用了 EntityFramework 5.0 和 "EF Designer from Database" 方法。在 C# 中为我的存储过程自动生成的代码如下所示:

        public virtual ObjectResult<P_GET_SEARCHCLIENTS_Result> P_GET_SEARCHCLIENTS(Nullable<decimal> i_IIN, string i_FULL_NAME, Nullable<System.DateTime> i_CREATED_AT_FROM, Nullable<System.DateTime> i_CREATED_AT_TO)
    {
        var i_IINParameter = i_IIN.HasValue ?
            new ObjectParameter("I_IIN", i_IIN) :
            new ObjectParameter("I_IIN", typeof(decimal));

        var i_FULL_NAMEParameter = i_FULL_NAME != null ?
            new ObjectParameter("I_FULL_NAME", i_FULL_NAME) :
            new ObjectParameter("I_FULL_NAME", typeof(string));

        var i_CREATED_AT_FROMParameter = i_CREATED_AT_FROM.HasValue ?
            new ObjectParameter("I_CREATED_AT_FROM", i_CREATED_AT_FROM) :
            new ObjectParameter("I_CREATED_AT_FROM", typeof(System.DateTime));

        var i_CREATED_AT_TOParameter = i_CREATED_AT_TO.HasValue ?
            new ObjectParameter("I_CREATED_AT_TO", i_CREATED_AT_TO) :
            new ObjectParameter("I_CREATED_AT_TO", typeof(System.DateTime));

        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<P_GET_SEARCHCLIENTS_Result>("P_GET_SEARCHCLIENTS", i_IINParameter, i_FULL_NAMEParameter, i_CREATED_AT_FROMParameter, i_CREATED_AT_TOParameter);
    }

如您所见,我在数据库中有 created_at 类型 timestamp 的列,它负责存储记录的创建日期。 因此,在我的应用程序中,我形成了 DateTime 参数(从 timestmap 到 DateTime 的转换),这些参数应该发送给 SP。

DateTime? i_createdAtFrom = null;
DateTime? i_createdAtTo = null;
if (long.TryParse(createdAtFrom, out long parsedFromDate))
    i_createdAtFrom = DateTimeOffset.FromUnixTimeSeconds(parsedFromDate).LocalDateTime;
if (long.TryParse(createdAtTo, out long parsedToDate))
    i_createdAtTo = DateTimeOffset.FromUnixTimeSeconds(parsedToDate).LocalDateTime;

该过程正常运行,没有任何错误,但是当我发送任何 createdAtFromcreatedAtTo 参数时,数据库抛出以下异常。

"ORA-00604: error occurred at recursive SQL level 1\nORA-01003: no statement parsed"

我认为这与将 C# DateTime 类型转换为 Oracle timestamp 的过程有某种联系,但我无法自行调试。

有什么想法吗?

我的配置:
Visual Studio 2017
EntityFramework 5.0
Oracle 客户端 11g 32 位

您应该使用准备好的语句和绑定参数。为了处理 NULL 值,您可以这样做:

-- Base query string.
query_str := 'select * from t_client where ';

-- Add search by IIN column to the query.
if i_iin is not null then
  query_str := query_str || 'iin like :iin ';
else
  query_str := query_str || ':iin IS NULL ';
end if;

-- Add search by FULL_NAME column to the query.
if i_full_name is not null then
  query_str := query_str || 'and lower(full_name) like :i_full_name ';
else
  query_str := query_str || 'and :i_full_name IS NULL ';
end if;

-- Add search range by the CREATED_AT column to the query.
if i_created_at_from is not null and i_created_at_to is not null then
  query_str :=
  query_str || 'and created_at >= :i_created_at_from and created_at <= :i_created_at_to ';
elsif i_created_at_from is not null and i_created_at_to is null then
    query_str := query_str || 'and created_at >= :i_created_at_from AND :i_created_at_to IS NULL ';
elsif i_created_at_from is null and i_created_at_to is not null then
    query_str := query_str || 'and created_at <= :i_created_at_to AND :i_created_at_from IS NULL ';
else
    query_str := query_str || 'and :i_created_at_from IS NULL AND :i_created_at_to IS NULL ';
end if;

-- Execute statement.
open result_cursor 
   for query_str 
   USING '%'||iin||'%', '%'||LOWER(i_full_name)||'%', i_created_at_from, i_created_at_to;