1

编辑:

解决方案是创建一个镜像相关表的视图,并将日期转换为 varchar,然后使用匹配的排序规则将其转换回日期

编辑结束

谁能告诉我为什么 OData4j 从我的一个 WCF 数据服务服务器读取日期时间值但在从另一个 WCF 数据服务读取具有相同格式的完全相同的日期时间类型时遇到非法参数异常(错误的 valueString 作为 keyString 的一部分)?

java.lang.IllegalArgumentException: bad valueString [datetime'2012-01-24T14%3A57%3A22.243'] 作为 keyString 的一部分

另一个问题是,当我从 OData4j 读取日期时间类型没有问题的服务请求 JSON 响应时,我得到另一个非法参数异常,错误消息是 - 奇数个字符。

java.lang.IllegalArgumentException:org.odata4j.repack.org.apache.commons.codec.DecoderException:奇数个字符。

因为 WCF 数据服务不能有多个源,所以我制作了 2 个项目,每个项目都有自己的实体数据模型源(来自现有数据库)。就像我上面提到的,我遇到了这些烦人的错误。

总结...

示例 1:作为 keyString 一部分的错误 valueString - 读取日期时间时。也发生在FormatType.JSON.

ODataConsumer customerInfoServices = ODataConsumer
                                     .newBuilder("http://10.0.2.2:41664/CustomerInfoWCFDataServices.svc/")
                                     .setFormatType(FormatType.ATOM)
                                     .build();

customer = customerInfoServices
           .getEntities("Customers")
           .select("name, id")
           .filter("id eq " + 5)
           .execute()
           .firstOrNull();

示例 2:奇数个字符。只有在FormatType.JSON读取日期时间时才发生并且没有问题。

ODataConsumer businessServices = ODataConsumer
                                 .newBuilder("http://10.0.2.2:35932/BusinessWCFDataServices.svc/")
                                 .setFormatType(FormatType.JSON)
                                 .build();

Enumerable<?> ordrer = businessServices
                       .getEntities("Orders")
                       .filter("custId eq " + customer.getProperty("id").getValue())
                       .execute();

我想要的是接收 JSON 响应(对于 android,ATOM 仍然过于繁琐)并且读取日期时间属性没有问题。


没有人能帮助我吗?

我一直在努力在谷歌上找到解决方案,但没有任何运气。

没有日期时间问题的数据库的排序规则是“Danish_Norwegian_CI_AS”,而有读取错误的数据库的排序规则是“SQL_Danish_Pref_CP1_CI_AS”。我不知道这是否有任何意义,但我怀疑它与它有关。

4

2 回答 2

0

解决方案是创建一个镜像相关表的视图,并将日期转换为 varchar,然后使用匹配的排序规则将其转换回日期。:-)

于 2012-03-09T11:53:02.233 回答
0

我今天遇到了这个问题,经过大约三个小时的谷歌搜索和查看代码后,我设法弄清楚发生了什么。这是我的设置/情况以及我发现的内容:

设置

  1. (OData 服务)Windows Server 2012 上使用默认应用程序池的 Microsoft IIS 8.0。
  2. (OData Producer)使用实体框架和 Web 数据服务的 Microsoft WCF 中间层。
  3. (OData 消费者)使用 OData4J v0.8 SNAPSHOT 的 Android 客户端。

问题

在我的中间层(OData 生产者)中,我使用 Entity Framework 5.0 来定义一个带有Edm.DateTime列的简单表。我的MessageTable.edmx文件生成一个简单的表:

CREATE TABLE [dbo].[MessageTable] (
    [Id] int IDENTITY(1,1) NOT NULL,
    [Date1] datetime NULL
);

在我的中间层的 WCF 数据服务(OData Producer)中,我从我的 Android 客户端应用程序中截获了 OData POST。我使用一些 C# 代码在中间层手动设置 Date1 列:

    private static void ProcessMessage(ODataMessage message)
    {
        .
        .
        .
        conn.Open();
        cmd.ExecuteNonQuery();
        int returnCode = (int)cmd.Parameters["@result"].Value;
        if (returnCode == 0)
        {
            message.Processed = true;
            message.Date1 = DateTime.Now;
        }
        .
        .
        .
    }

请注意,我使用了 C# 的DateTime.Now静态属性。MSDN 文档指出DateTime.Now

获取一个 DateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间

要实现的关键是本地时间意味着 C# 日期时间结构现在包含本地时区信息。

因此,在中间层代码完成后,WCF 服务将 OData POST 插入到我的表中。然后,Microsoft 将该[Date1]列发送回我的 Android 客户端(OData 消费者)。Microsoft 似乎将日期编码为 OData DateTimeOffset,因为它包含本地时区信息。即作为2013-08-26T17:30:00.0000000-7:00

编码

在 OData4j 中有一个包org.odata.internal可以处理解析 OData 日期时间字符串。在 0.6 版中,我在第 40-44 行发现了以下关于DATETIME_PATTERN用于解析日期时间字符串的正则表达式模式的评论:

40   // Since not everybody seems to adhere to the spec, we are trying to be
41   // tolerant against different formats
42   // spec says:
43   // Edm.DateTime: yyyy-mm-ddThh:mm[:ss[.fffffff]]
44   // Edm.DateTimeOffset: yyyy-mm-ddThh:mm[:ss[.fffffff]](('+'|'-')hh':'mm)|'Z'
45   private static final Pattern DATETIME_PATTERN =
46       Pattern.compile("(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})(:\\d{2})?(\\.\\d{1,7})?((?:(?:\\+|\\-)\\d{2}:\\d{2})|Z)?");
47 
48

在 OData4j v0.7 中,DATETIME_PATTERN已变为DATETIME_XML_PATTERN

40 
41   private static final Pattern DATETIME_XML_PATTERN = Pattern.compile("" +
42       "^" +
43       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})" + // group 1 (datetime)
44       "(:\\d{2})?" + // group 2 (seconds)
45       "(\\.\\d{1,7})?" + // group 3 (nanoseconds)
46       "(Z)?" + // group 4 (tz, ignored - handles bad services)
47       "$");
48 
49   private static final Pattern DATETIMEOFFSET_XML_PATTERN = Pattern.compile("" +
50       "^" +
51       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})" + // group 1 (datetime)
52       "(\\.\\d{1,7})?" + // group 2 (nanoSeconds)
53       "(((\\+|-)\\d{2}:\\d{2})|(Z))" + // group 3 (offset) / group 6 (utc)
54       "$");

我认为第 46 行的评论解释了一切:

... // 第 4 组(tz,忽略 - 处理不良服务)

我将其解释为“任何时区信息都将被忽略 - 这会处理发送时区信息的不良服务(即 Microsoft)”

在我看来,OData4j 作者决定坚持他们的立场,只接受正确的Edm.DateTime字符串格式。

解决方案

如果您有权访问 OData Producer 代码,则修复非常简单:

    private static void ProcessMessage(ODataMessage message)
    {
        .
        .
        .
        conn.Open();
        cmd.ExecuteNonQuery();
        int returnCode = (int)cmd.Parameters["@result"].Value;
        if (returnCode == 0)
        {
            message.Processed = true;
            message.Date1 = DateTime.UtcNow;
        }
        .
        .
        .
    }

请改用DateTime.UtcNow属性。MSDN 文档指出:

获取一个 DateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为协调世界时 (UTC)

如果您无权访问 OData 生产者,我能看到的唯一解决方案是更改 OData4j 代码。更改正则表达式模式DATETIME_XML_PATTERN

41   private static final Pattern DATETIME_XML_PATTERN = Pattern.compile("" +
42       "^" +
43       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})" + // group 1 (datetime)
44       "(:\\d{2})?" + // group 2 (seconds)
45       "(\\.\\d{1,7})?" + // group 3 (nanoseconds)
46       "((?:(?:\\+|\\-)\\d{2}:\\d{2})|Z)?" + 
47       "$");

结论

我认为这实际上是微软的一个错误。我确信他们有一些相关的理由来发送一个,Edm.DateTimeOffset但我的MessageTable.edmx文件指定[Date1]为一个Edm.DateTime,所以我认为微软代码应该为我转换为 UTC,或者抛出一个异常。一个异常会警告我我使用了不正确的 DateTime 结构并帮助我更快地看到 DateTime.UtcNow 解决方案。

于 2013-08-28T00:55:36.763 回答