我有C#程序,其中所有DateTime
个对象都是DateTimeKind.UTC
。将对象保存到数据库时,它按预期存储UTC。但是,在检索它们时,它们是DateTimeKind.Unspecified
。在C#中创建DateTime
个对象以始终使用DateTimeKind.UTC
时,有没有办法告诉实体框架(代码优先)?
答案 0 :(得分:16)
不,没有。它实际上是DateTimeKind.Unspecified
。
但是,如果您担心支持多个时区,则应考虑使用DateTimeOffset。它就像一个常规的DateTime,除了它不代表时间的“视角”,它代表一个绝对视图,其中下午3点(UTC - 3)等于下午4点(UTC - 2)。 DateTimeOffset包含DateTime和时区,并且EntityFramework和SQL Server都支持它。
答案 1 :(得分:7)
您可以让您的datacontext修复所有相关值。以下是实体类型的属性缓存,以避免每次都检查类型:
public class YourContext : DbContext
{
private static readonly List<PropertyInfo> EmptyPropsList = new List<PropertyInfo>();
private static readonly Hashtable PropsCache = new Hashtable(); // Spec promises safe for single-reader, multiple writer.
// Spec for Dictionary makes no such promise, and while
// it should be okay in this case, play it safe.
private static List<PropertyInfo> GetDateProperties(Type type)
{
List<PropertyInfo> list = new List<PropertyInfo>();
foreach(PropertyInfo prop in type.GetProperties())
{
Type valType = prop.PropertyType;
if(valType == typeof(DateTime) || valType == typeof(DateTime?))
list.Add(prop);
}
if(list.Count == 0)
return EmptyPropsList; // Don't waste memory on lots of empty lists.
list.TrimExcess();
return list;
}
private static void FixDates(object sender, ObjectMaterializedEventArgs evArg)
{
object entity = evArg.Entity;
if(entity != null)
{
Type eType = entity.GetType();
List<PropertyInfo> rules = (List<PropertyInfo>)PropsCache[eType];
if(rules == null)
lock(PropsCache)
PropsCache[eType] = rules = GetPropertyRules(eType); // Don't bother double-checking. Over-write is safe.
foreach(var rule in rules)
{
var info = rule.PropertyInfo;
object curVal = info.GetValue(entity);
if(curVal != null)
info.SetValue(entity, DateTime.SpecifyKind((DateTime)curVal, rule.Kind));
}
}
}
public YourContext()
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += FixDates;
/* rest of constructor logic here */
}
/* rest of context class here */
}
这也可以与属性结合使用,以便通过存储关于每个属性的一组规则,而不仅仅是DateTimeKind
来设置每个属性应该具有的PropertyInfo
,并且对于GetDateProperties
中的属性。
答案 2 :(得分:3)
我的解决方案,首先使用代码: 以这种方式声明DateTime属性:
private DateTime _DateTimeProperty;
public DateTime DateTimeProperty
{
get
{
return _DateTimeProperty;
}
set
{
_DateTimeProperty = value.ToKindUtc();
}
}
也可以创建属性:
private DateTime? _DateTimeProperty;
public DateTime? DateTimeProperty
{
get
{
return _DateTimeProperty;
}
set
{
_DateTimeProperty = value.ToKindUtc();
}
}
ToKindUtc()
是将DateTimeKind.Unspecified
更改为DateTimeKind.Utc
的扩展程序,如果是ToUniversalTime()
,则可致电DateTimeKind.Local
这里是扩展的代码:
public static class DateTimeExtensions
{
public static DateTime ToKindUtc(this DateTime value)
{
return KindUtc(value);
}
public static DateTime? ToKindUtc(this DateTime? value)
{
return KindUtc(value);
}
public static DateTime ToKindLocal(this DateTime value)
{
return KindLocal(value);
}
public static DateTime? ToKindLocal(this DateTime? value)
{
return KindLocal(value);
}
public static DateTime SpecifyKind(this DateTime value, DateTimeKind kind)
{
if (value.Kind != kind)
{
return DateTime.SpecifyKind(value, kind);
}
return value;
}
public static DateTime? SpecifyKind(this DateTime? value, DateTimeKind kind)
{
if (value.HasValue)
{
return DateTime.SpecifyKind(value.Value, kind);
}
return value;
}
public static DateTime KindUtc(DateTime value)
{
if (value.Kind == DateTimeKind.Unspecified)
{
return DateTime.SpecifyKind(value, DateTimeKind.Utc);
}
else if (value.Kind == DateTimeKind.Local)
{
return value.ToUniversalTime();
}
return value;
}
public static DateTime? KindUtc(DateTime? value)
{
if (value.HasValue)
{
return KindUtc(value.Value);
}
return value;
}
public static DateTime KindLocal(DateTime value)
{
if (value.Kind == DateTimeKind.Unspecified)
{
return DateTime.SpecifyKind(value, DateTimeKind.Local);
}
else if (value.Kind == DateTimeKind.Utc)
{
return value.ToLocalTime();
}
return value;
}
public static DateTime? KindLocal(DateTime? value)
{
if (value.HasValue)
{
return KindLocal(value.Value);
}
return value;
}
}
请记住包含在模型的文件中。
using TheNameSpaceWhereClassIsDeclared;
使用EF从数据库读取时,或者在MVC控制器的编辑方法中分配属性时,将调用set属性方法。
警告,如果在网络表单中,如果您在本地时区编辑日期,则必须在发送到服务器之前将日期转换为UTC。
答案 3 :(得分:1)
在这里查看michael.aird答案:https://stackoverflow.com/a/9386364/279590 它在加载期间标记UTC种类,并在ObjectMaterialized上标记事件。