我已经针对 2008 数据库构建了一个实体框架模型。对于 2008 数据库,一切正常。当我尝试更新 2005 数据库上的实体时,我收到此错误。
使用的 SQL Server 版本不支持数据类型 'datetime2
我在构建数据库时特别没有使用任何 2008 功能。我在代码中找不到对 datetime2 的任何引用。而且,是的,该列在数据库中被定义为“日期时间”。
我已经针对 2008 数据库构建了一个实体框架模型。对于 2008 数据库,一切正常。当我尝试更新 2005 数据库上的实体时,我收到此错误。
使用的 SQL Server 版本不支持数据类型 'datetime2
我在构建数据库时特别没有使用任何 2008 功能。我在代码中找不到对 datetime2 的任何引用。而且,是的,该列在数据库中被定义为“日期时间”。
一个快速的谷歌向我指出了解决方案的样子。
在文件编辑器中打开您的 EDMX(或在 Visual Studio 中“打开方式...”并选择 XML 编辑器)。在顶部,您会找到存储模型,它有一个属性 ProviderManifestToken。这应该具有值 2008。将其更改为 2005,重新编译,一切正常。
注意:每次从数据库更新模型时都必须这样做。
快速查看线路:
<Schema Namespace="Foobar.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" >
这非常令人沮丧,我很惊讶 MS 决定不这样做,以便您可以针对给定的 SQL 版本。为了确保我们的目标是 2005,我编写了一个简单的控制台应用程序并在 PreBuild 步骤中调用它。
预构建步骤如下所示:
$(SolutionDir)Artifacts\SetEdmxVer\SetEdmxSqlVersion $(ProjectDir)MyModel.edmx 2005
代码在这里:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace SetEdmxSqlVersion
{
class Program
{
static void Main(string[] args)
{
if (2 != args.Length)
{
Console.WriteLine("usage: SetEdmxSqlVersion <edmxFile> <sqlVer>");
return;
}
string edmxFilename = args[0];
string ver = args[1];
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(edmxFilename);
XmlNamespaceManager mgr = new XmlNamespaceManager(xmlDoc.NameTable);
mgr.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2008/10/edmx");
mgr.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl");
XmlNode node = xmlDoc.DocumentElement.SelectSingleNode("/edmx:Edmx/edmx:Runtime/edmx:StorageModels/ssdl:Schema", mgr);
if (node == null)
{
Console.WriteLine("Could not find Schema node");
}
else
{
Console.WriteLine("Setting EDMX version to {0} in file {1}", ver, edmxFilename);
node.Attributes["ProviderManifestToken"].Value = ver;
xmlDoc.Save(edmxFilename);
}
}
}
}
使用上面的@Vance 方便的控制台应用程序,我将以下内容用作 BeforeBuild 事件
<Target Name="BeforeBuild">
<!--Check out BD.edmx, Another.edmx, all configs-->
<Exec Command="$(SolutionDir)\Library\tf checkout /lock:none $(ProjectDir)Generation\DB.edmx" />
<Exec Command="$(SolutionDir)\Library\tf checkout /lock:none $(ProjectDir)Generation\Another.edmx" />
<!--Set to 2008 for Dev-->
<Exec Condition=" '$(Configuration)' == 'DEV1' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\DB.edmx 2008" />
<Exec Condition=" '$(Configuration)' == 'DEV1' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\Another.edmx 2008" />
<Exec Condition=" '$(Configuration)' == 'DEV2' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\DB.edmx 2008" />
<Exec Condition=" '$(Configuration)' == 'DEV2' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\Another.edmx 2008" />
<!--Set to 2005 for Deployments-->
<Exec Condition=" '$(Configuration)' == 'TEST' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\DB.edmx 2005" />
<Exec Condition=" '$(Configuration)' == 'TEST' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\Another.edmx 2005" />
<Exec Condition=" '$(Configuration)' == 'PRODUCTION' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\DB.edmx 2005" />
<Exec Condition=" '$(Configuration)' == 'PRODUCTION' " Command="$(SolutionDir)Library\SetEdmxSqlVersion $(ProjectDir)Generation\Another.edmx 2005" />
</Target>
这非常方便,可以避免烦人的重新部署。感谢分享万斯。
我已将 TF.exe 添加到库解决方案文件夹中,这很有帮助,因为我现在可以在尝试编辑它们之前检查 edmx 文件,作为构建的一部分。此外,我还添加了条件,以便将其设置为 2005 用于部署到服务器,并设置为 2008 用于开发机器 sln 配置。还要提一下,您需要将实际的 SetEdmxSqlVersion.exe(和 .pdb)文件添加到库文件夹(或您想要保留这些位的任何其他位置)。
非常感谢@Vance。非常整洁,节省大量时间,并使我的构建完全自动化且无痛:)
2012 年与 2008 年有类似的问题。它可以通过使用 XmlPeek 和 XmlPoke 的 BeforeBuild 事件来解决:
<Target Name="BeforeBuild">
<XmlPeek XmlInputPath="$(ProjectDir)MyModel.edmx"
Namespaces="<Namespace Prefix='edmx' Uri='http://schemas.microsoft.com/ado/2009/11/edmx'/><Namespace Prefix='ssdl' Uri='http://schemas.microsoft.com/ado/2009/11/edm/ssdl'/>"
Query="/edmx:Edmx/edmx:Runtime/edmx:StorageModels/ssdl:Schema/@ProviderManifestToken">
<Output TaskParameter="Result" ItemName="TargetedSQLVersion" />
</XmlPeek>
<XmlPoke Condition="@(TargetedSQLVersion) != 2008"
XmlInputPath="$(ProjectDir)MyModel.edmx"
Namespaces="<Namespace Prefix='edmx' Uri='http://schemas.microsoft.com/ado/2009/11/edmx'/><Namespace Prefix='ssdl' Uri='http://schemas.microsoft.com/ado/2009/11/edm/ssdl'/>"
Query="/edmx:Edmx/edmx:Runtime/edmx:StorageModels/ssdl:Schema/@ProviderManifestToken"
Value="2008">
</XmlPoke>
</Target>
如果您不喜欢自动替换,您可以简单地将 XmlPoke 任务替换为错误任务。
为了让遇到相同问题但使用Code First的人受益,请在此处查看我的回答,了解如何更改ProviderManifestToken
Code First 中的内容。它涉及在调用模型构建器的方法时DbModelBuilder
手动创建一个实例并传递一个DbProviderInfo
实例(使用适当的令牌) 。Build
对我来说更好的解决方案不是手动编辑 EDMX 文件,而是在设计模式和上下文菜单“从数据库更新模型...”中打开 edmx。当然,无论这对您来说是什么,您都必须指向正确的 SQL 版本。
我们在 SQL2005 v.3 上遇到了这个错误,而在 SQL2005 v.4 上没有。
将 SQL2005 添加到连接字符串解决了我们的特定问题。
我们尚未确定原因,也不想修改代码以提供上述解决的令牌(部署期间出现的问题)。