LINQ2SQL:如何在加载匿名实体时修改字段值?
!!!请不要重定向到this article,因为它不能解决下面描述的问题。LINQ2SQL:如何在加载匿名实体时修改字段值?
比方说,我们在数据库中有这样的表:
SomeTable
- ID(INT)
- DT(日期时间)
我们已经配置了一个LINQ2SQL数据上下文。并且我们已经为SomeTable配置了一个实体:OnLoaded方法修改了DT,使DT的DateTimeKind成为Utc(最初是Unspecified)。
现在,这里的问题是:
如果我们用整个实体请求数据时,装载的方法被称为:
From x In ourDataContext.SomeTable Select x
但是,如果我们只请求表的一部分(并因此产生一个匿名型),将装载的不叫:
From x In ourDataContext.SomeTable Select x.DT
很清楚,装载的是SomeTable实体定义,而不是匿名类型。
目前我考虑创建将取代匿名类型的自定义实体。但也许有人有更好的解决方案?
我们有类似的问题,因为我们需要从实体接收部分字段作为匿名对象,并且始终知道我们有日期字段的DateTimeKind
作为DateTimeKind.UTC
而不使用LINQ请求中的附加功能。
我们尝试了很多东西,但是我们发现只有一个足够好的解决方案 - 使用T4为Linq2Sql生成代码。
P.S.如果您想了解更多关于使用T4生成Linq2Sql代码的信息,您可以从http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
你可以指定查询中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的想法。如果某些开发人员忘记使用AsUtc,那么他将收到不正确的数据。 – Dima
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在这里提供了一些灵活性(如上所示),但如果解决方案不令人满意,还有其他选择:
- L2S DAL上方的显式层。通常情况下,它是一个存储库模式 ,它返回的DTO非常类似于L2S自动生成的DTO。在这种情况下,您可以隐藏
DT
财产,强制消费者仅使用CustomDT
。 - 将逻辑放入数据库(视图,计算列,SP)。 I 不会将这种方法用于新项目,但它可能是某些传统应用程序的可行选项。
这种方法在问题中有所描述,但我正在寻找更好的方法。 – Dima
我看不出问题如何描述使用额外的属性来解决您的问题。它适用于投影(如示例)和选择场景。 – UserControl
好吧,很简单:我们必须引入自定义代码,这有两个缺点: 1.第三方开发者仍然不能直接使用DT属性(因此整个自动DT属性的想法被打破) 2.使用CustomDT在查询中,LINQ2SQL跳过优化:它从数据库请求所有表字段,而不是只请求DT字段。 – Dima
您可以使用linq-to-sql
的查询部分,并使用linq-to-objects
抓住你想要的属性DateTime
(你实际上并没有返回一个匿名类型)。
(From x In ourDataContext.SomeTable _
Select x).AsEnumerable() _
.Select(Function(x) x.DT)
你可以试试这段代码吗?您可以指定相同的表类型,但只加载一个字段,而不使用匿名类型。我不知道你的情况是否会起作用。
SomeTable.Select(x => new SomeTable {
DateField = x.DateField
})
否则没有简单的解决方案。
我想这是现在唯一的方法...:/ – Dima