LINQ2SQL:加载匿名实体时如何修改字段值?

LINQ2SQL: How to modify fields values when loading anonymous entities?

!!!请不要重定向到 this article,因为它不能解决下面描述的问题。

假设我们在数据库中有这样的table:

SomeTable

我们已经配置了 Linq2Sql 数据上下文。我们为 SomeTable 配置了一个实体:OnLoaded 方法修改 DT,使 DT 的 DateTimeKind 变为 Utc(最初它是未指定的)。

现在问题来了:

如果我们使用整个实体请求数据,调用OnLoaded方法:

From x In ourDataContext.SomeTable Select x

但是如果我们只请求 table 的一部分(因此生成匿名类型),则不会调用 OnLoaded:

From x In ourDataContext.SomeTable Select x.DT

很明显OnLoaded是在SomeTable实体中定义的,而不是匿名类型。

目前我正在考虑创建自定义实体来替换匿名类型。但也许有人有更好的解决方案?

您可以在查询中指定 DateTimeKind

from x in ourDataContext.SomeTable 
select DateTime.SpecifyKind(x.DT, DateTimeKind.Utc)

如果您经常这样做,扩展方法可能有助于减少冗长:

public static class Ext
{
    public static DateTime AsUtc(this DateTime dateTime)
    {
        return DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
    }

    public static DateTime? AsUtc(this DateTime? dateTime)
    {
        if(dateTime == null) return null;
        return AsUtc(dateTime.Value);
    }
}

那么您的查询变为:

from x in ourDataContext.SomeTable select x.DT.AsUtc()

Linq2Sql 为表生成部分 类,因此非常容易扩展。只需将 SomeTable.cs 文件添加到您的解决方案中(在与自动生成的数据库上下文相同的命名空间内)并定义一个额外的 属性 以及您需要的任何行为:

public partial class SomeTable {
    public System.DateTime CustomDT {
        get { return DT.AddYears(120); }
    }
}

现在可以正常查询了:

        var e = ctx.SomeTable.Select(x => new { x.CustomDT }).First();
        Console.WriteLine(e.CustomDT);

更新:

根据评论,我认为您面临的问题是由于职责分离不正确造成的。您正在尝试将业务逻辑(数据转换)责任传递给您的 DAL。虽然 L2S 在这里提供了一些灵活性(如上所示),但如果解决方案不令人满意,您还有其他选择:

  1. L2S DAL 之上的显式层。通常它是一个存储库模式 returns DTO 与 L2S 自动生成的非常相似。在这种情况下,您可以隐藏 DT 属性 强制消费者仅使用 CustomDT
  2. 将逻辑放入数据库(视图、计算列、SP)。我 不会考虑将这种方法用于新项目,但它可能是 一些遗留应用程序的可行选择。

您可以使用 linq-to-sql 作为查询部分,并使用 linq-to-objects 获取您想要的 DateTime 属性(您实际上并没有返回匿名类型)。

(From x In ourDataContext.SomeTable _
 Select x).AsEnumerable() _
          .Select(Function(x) x.DT)

你能试试这个代码吗?您可以指定相同的 Table 类型,但只加载一个字段,而不是使用匿名类型。我不知道它是否适用于你的情况。

SomeTable.Select( x => new SomeTable {
    DateField = x.DateField
})

否则没有简单的解决办法

我们遇到了类似的问题,因为我们需要从实体接收部分字段作为匿名对象,并且始终知道我们有 DateTimeKind 个日期字段作为 DateTimeKind.UTC,而无需在 LINQ 请求中使用其他函数。

我们尝试了很多东西,但我们只找到了一个足够好的解决方案 - 使用 T4 为 Linq2Sql 生成代码。

P.S.如果想了解更多关于使用T4生成Linq2Sql代码,可以从http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

开始