使用Entity Framework Database First强制指定DateTime

3
我正在使用EF数据库优先连接到数据库。因此,我的模型是自动生成的。
当我更新记录时,我的DateTimes会被写入SQL类型DateTime2。生产服务器是SQL Server 2005(请不要评论),因此更新失败,因为不支持DateTime2。
我尝试为我的模型创建元数据类,如http://www.asp.net/mvc/overview/getting-started/database-first-development/enhancing-data-validation所述,并用[Column(DbType = "datetime")]装饰成员,但我可能没有正确遵循说明或走上了错误的道路。
如何让EF优先数据库在写入数据库时使用DateTime?
谢谢
3个回答

3

我曾经遇到过这个问题,因为Entity Framework标准的DateTime是DateTime2字段。解决方法是将SQL Server数据库中的所有列更新为datetime2,但是datetime2数据类型仅在SQL Server 2008中引入,所以有几个尝试方法:

第一步:确保你的SQL数据库中的DateTime字段可以为空,如果是,则使用"DateTime?"(可空的日期时间)而不是"DateTime"。

第二步:用任何XML编辑器(Visual Studio应该可以)打开EDMX文件,并将ProviderManifestToken的值更改为ProviderManifestToken="2005",这应该确保与SQL Server 2005兼容。

这适用于.edmx文件,但对于Code First,更改会更具挑战性,并且取决于您的Entity Framework版本,因此Microsoft建议尝试在OnModelCreating方法中指定列类型,例如以下示例:

modelBuilder.Entity<Blog>().Property(t => t.CreatedOn).HasColumnName("CreatedOn").HasColumnType("date");

尝试通过改变ColumnType的值来达到你的目标。

如果你仍然想要更改你的ProviderManifestToken值:

E.F. 6: 你可以为你的DbContext创建一个配置,基本上是这样的一个类:

/// <summary>
/// A configuration class for SQL Server that specifies SQL 2005 compatability.
/// </summary>
internal sealed class EntityFrameworkDbConfiguration : DbConfiguration
{
    /// <summary>
    /// The provider manifest token to use for SQL Server.
    /// </summary>
    private const string SqlServerManifestToken = @"2005";

    /// <summary>
    /// Initializes a new instance of the <see cref="EntityFrameworkDbConfiguration"/> class.
    /// </summary>
    public EntityFrameworkDbConfiguration()
    {
        this.AddDependencyResolver(new SingletonDependencyResolver<IManifestTokenResolver>(new ManifestTokenService()));
    }

    /// <inheritdoc />
    private sealed class ManifestTokenService : IManifestTokenResolver
    {
        /// <summary>
        /// The default token resolver.
        /// </summary>
        private static readonly IManifestTokenResolver DefaultManifestTokenResolver = new DefaultManifestTokenResolver();

        /// <inheritdoc />
        public string ResolveManifestToken(DbConnection connection)
        {
            if (connection is SqlConnection)
            {
                return SqlServerManifestToken;
            }

            return DefaultManifestTokenResolver.ResolveManifestToken(connection);
        }
    }
}

使用方法:

DbConfigurationType(typeof(EntityFrameworkDbConfiguration))]
public class MyContextContext : DbContext
{
}

(来源:如何配置 EF Code First 的 ProviderManifestToken
E.F. 5 及更早版本:阅读这篇文章可以很容易地澄清:http://blog.oneunicorn.com/2012/04/21/code-first-building-blocks/ 希望对您有所帮助。

1
需要注意的是,直接编辑 edmx 文件将在下次验证模型时被覆盖。因此不应该使用这种方法。我喜欢使用 DbConfiguration 的方式。 - Hopeless
这看起来很有前途。不幸的是,自定义的DbConfiguration类似乎被完全忽略了。我正在使用EF 6.1.3。 - David Hyde
David,你尝试在OnModelCreating方法中指定列类型了吗? - Felippe Rangel

3

很遗憾,Felippe的建议没有起作用,尽管我看不出任何原因。

我设法想出了自己的解决方案。虽然不完全满意,但我们正在努力让客户升级到SQL Server 2014,所以它不是永久性的。欢迎评论...

首先我创建了这个类:

internal sealed class MyCommandInterceptor : IDbCommandInterceptor
{
    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        ChangeDateTime2ToDateTimeForSqlServer2005Compatibility(command);
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        ChangeDateTime2ToDateTimeForSqlServer2005Compatibility(command);
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        ChangeDateTime2ToDateTimeForSqlServer2005Compatibility(command);
    }

    /// <summary>
    /// Changes parameters of type datetime2 to datetime for SQL server2005 compatibility.
    /// </summary>
    /// <param name="command">The command.</param>
    private void ChangeDateTime2ToDateTimeForSqlServer2005Compatibility(DbCommand command)
    {
        foreach (DbParameter param in command.Parameters)
        {
            if (param.DbType == System.Data.DbType.DateTime2)
            {
                param.DbType = System.Data.DbType.DateTime;
            }
        }
    }
}

我在我的DbContext派生类中使用静态构造函数来激活它:

    static MyDbContext()
    {
        // The command interceptor changes DateTime2 data types to DateTime for SQL Server 2005 compatibility.
        DbInterception.Add(new MyCommandInterceptor());
    }

我会认真监控这个,以确保它的表现符合要求。


0

我通过删除数据库并在包管理器控制台中再次运行update-database命令来解决它。虽然不适用于生产环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接