突然,在实例化生成的ObjectContext类时,我一直得到一个MetadataException。App.Config中的连接字符串看起来是正确的-自从上次它工作以来没有改变-我已经尝试从底层数据库中重新生成一个没有变化的新模型(edmx-file)。
有人有什么想法吗?
进一步的细节:我没有更改任何属性,没有更改任何输出程序集的名称,也没有尝试将EDMX嵌入到程序集中。我只是下班后等了10个小时才回来。然后它就不管用了。
我试过重新创造EDMX。我试着重新创建这个项目。我甚至尝试从头开始重新创建数据库。不管怎样,运气不好。
当Edmx在一个项目中,而您正在从另一个项目中使用它时,可以得到此异常。
原因是Res://*/是一个指向当前程序集中资源的uri。如果Edm是在与使用它的代码不同的程序集中定义的,res://*/将不起作用,因为无法找到资源。
您需要提供程序集的全名(包括公钥令牌),而不是指定' * '。例如:
res://YourDataAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=abcdefabcedf/YourEdmxFileName.csdl|res://...
构造连接字符串的更好方法是使用EntityConnectionStringBuilder:
public static string GetSqlCeConnectionString(string fileName)
{
var csBuilder = new EntityConnectionStringBuilder();
csBuilder.Provider = "System.Data.SqlServerCe.3.5";
csBuilder.ProviderConnectionString = string.Format("Data Source={0};", fileName);
csBuilder.Metadata = string.Format("res://{0}/YourEdmxFileName.csdl|res://{0}/YourEdmxFileName.ssdl|res://{0}/YourEdmxFileName.msl",
typeof(YourObjectContextType).Assembly.FullName);
return csBuilder.ToString();
}
public static string GetSqlConnectionString(string serverName, string databaseName)
{
SqlConnectionStringBuilder providerCs = new SqlConnectionStringBuilder();
providerCs.DataSource = serverName;
providerCs.InitialCatalog = databaseName;
providerCs.IntegratedSecurity = true;
var csBuilder = new EntityConnectionStringBuilder();
csBuilder.Provider = "System.Data.SqlClient";
csBuilder.ProviderConnectionString = providerCs.ToString();
csBuilder.Metadata = string.Format("res://{0}/YourEdmxFileName.csdl|res://{0}/YourEdmxFileName.ssdl|res://{0}/YourEdmxFileName.msl",
typeof(YourObjectContextType).Assembly.FullName);
return csBuilder.ToString();
}
如果仍然遇到异常,请在reflector中打开程序集并检查.csdl、.ssdl和.msl文件的文件名。当资源与元数据值中指定的资源具有不同的名称时,将无法正常工作。
在我的情况下,这个问题与重命名我的模型的edmx文件有关…修正app.config连接字符串的csdl/ssdl/msl文件修复了我的问题。
如果您使用EF 4.0设计器来生成csdl/ssdl/msl,这3个“文件”实际上将存储在模型的主edmx文件中。在这种情况下,瓦卡斯的帖子几乎是正确的。重要的是要理解他示例中的“Model_Name”将需要更改为模型的.edmx文件的当前名称(不包含.edmx)。
此外,如果edmx文件不在项目的根级别,则需要在Model_Name前面加上相对路径,例如:
res://*/MyModel.WidgetModel.csdl|res://*/MyModel.WidgetModel.ssdl|res://*/MyModel.WidgetModel.msl
将指定csdl/ssdl/msl xml存储在模型文件'WidgetModel。它存储在名为“MyModel”的文件夹中。
我编写了这个helper类,当ObjectContext对象定义在与使用它的项目不同的项目中时,它可以创建对象的实例。我解析配置文件中的连接字符串,并将'*'替换为完整的程序集名称。
它并不完美,因为它使用反射来构建对象,但这是我能找到的最通用的方法。
希望它能帮助到别人。
public static class EntityHelper<T> where T : ObjectContext
{
public static T CreateInstance()
{
// get the connection string from config file
string connectionString = ConfigurationManager.ConnectionStrings[typeof(T).Name].ConnectionString;
// parse the connection string
var csBuilder = new EntityConnectionStringBuilder(connectionString);
// replace * by the full name of the containing assembly
csBuilder.Metadata = csBuilder.Metadata.Replace(
"res://*/",
string.Format("res://{0}/", typeof(T).Assembly.FullName));
// return the object
return Activator.CreateInstance(typeof(T), csBuilder.ToString()) as T;
}
}
对于所有SelftrackingEntities用户,
如果您已经遵循Microsoft演练并将Object上下文类分离为
WCF服务项目(通过链接到上下文.tt)所以这个答案是给你的:
这篇文章中显示的部分答案包括如下代码:
... = string.Format("res://{0}/YourEdmxFileName.csdl|res://{0}/YourEdmxFileName.ssdl|res://{0}/YourEdmxFileName.msl",
typeof(YourObjectContextType).Assembly.FullName);
对你没用!!原因是youobjectcontexttype。程序集现在驻留在不同的程序集(在wcf项目程序集内),
你应该用——>替换youobjectcontexttype。assembly。fullname
ClassTypeThatResidesInEdmProject.Assembly.FullName
玩得开心。
对我来说,我把数据访问层和用户界面层分开了。
每一层都有实体连接字符串。
在我将这两个分离的连接字符串修改为相同之前,我仍然发现下面的错误。
Unable to load the specified metadata resource
所以我让这两个层(DAL, UI)是相同的连接字符串,它的工作完美。
我的解决方案是使所有的连接字符串是相同的,无论他们已经提出。
我也有这个问题,这是因为我的网络中的连接字符串。config与我的EDMX所在程序集的app.config中的略有不同。不知道为什么会改变,但这里有两个不同的版本。
App.config:
<add name="SCMSEntities" connectionString="metadata=res://*/Model.SMCSModel.csdl|res://*/Model.SMCSModel.ssdl|res://*/Model.SMCSModel.msl;provider=System.Data.SqlClient;provider connection string="data source=SANDIEGO\sql2008;initial catalog=SCMS;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework"" providerName="System.Data.EntityClient" />
. config:
<add name="SCMSEntities" connectionString="metadata=res://*/Model.SCMSModel.csdl|res://*/Model.SCMSModel.ssdl|res://*/Model.SCMSModel.msl;provider=System.Data.SqlClient;provider connection string="data source=SANDIEGO\sql2008;initial catalog=SCMS;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
修复它只是简单地复制App .config字符串(注意结尾的小差异-而不是“App=EntityFramework”,它想要“应用程序名称=EntityFramework”)到web。解决了配置和问题。:)
当我得到元数据问题排序,我有一个后续的问题,形式是调用异常无法找到app.config中XXXEntities的连接字符串(其中我的目标是不依赖app.config)。幸运的是,我找到了引用系统。我的单元测试项目中的数据清除了最后的障碍。总结一下:
使用nuget将实体框架安装到单元测试项目中。
确保System. data . entity和System. data . entity。引用数据。
按照这里的描述对连接字符串进行排序。
将连接字符串传递给分部类构造函数。
现在我的元数据在一个类库中,这个类库可以从引用db更新,并且我可以在运行时将我的应用程序和单元测试指向任何服务器上的任何db。
附录:当我移动我的edmx到一个文件夹,我又得到了错误。经过一些研究,我发现您希望元数据字符串看起来像:metadata=res://EPM.DAL/Models.EPM。其中EPM. csdl。DAL是组装和EPM的名称。Edmx在models文件夹中。
和一个快速的方法来检查模型名称没有Reflector....查找目录
...obj - {} - edmxResourcesToEmbed输出配置
检查.csdl、.msl和.ssdl资源文件是否存在。如果它们在子目录中,则子目录的名称必须加在模型名称之前。
例如,我的三个资源文件在一个子目录Data中,所以我的连接字符串必须是
元= res: / / * Data.MyModel.csdl | res: / * / Data.MyModel.ssdl | res: / * / Data.MyModel.msl;
(与元= res: / / * / MyModel csdl | res: / / * / MyModel ssdl | res: / / * / MyModel msl;)。
我昨天遇到了这个问题,并在调试中查看了我的代码和SQL分析器的输出。
在我阅读和理解这篇文章之前,我不能理解的是,为什么EntityFramework在调用DB时抛出这个错误。我在SQL Profiler中查看了数百行,试图找出数据库模型的错误。我找不到我期待的那种电话,老实说,我也不确定我在找什么。
如果您处于此位置,请检查连接字符串。我的猜测是,在EntityFramework创建它的SQL之前,它会检查模型,在连接字符串的元数据部分指定。对我来说,这是错误的。EntityFramework甚至还没有到DB。
确保名字是正确的。一旦我得到了整理,我然后看到调用SQL Profiler的ApplicationName是'EntityFramework'与SQL调用预期的表。
使用这篇博文中的信息:
就像其他人说的,res:\\是指向资源的指针。要检查并确保您的资源名称是正确的,您可以使用JetBrains的DotPeek等反编译器打开您的.dll文件并查看资源文件。
或者,您可以在调试时打开监视窗口并粘贴此代码,以获得当前正在执行的程序集中的资源名称数组。
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames()
也就是说,元数据路径的格式应该是这样的:
{my-assembly-name} / {possibly-a-namespace},{类名称}。{csdl or SSDL or msl}
我的问题和解决方案,症状是相同的“无法加载指定的元数据资源”,但根本原因不同。我在解决方案中有两个项目,一个是EntityModel,另一个是解决方案。实际上,我在EntityModel中删除并重新创建了EDMX文件。
解决方案是,我必须回到Web应用程序项目,并将这一行添加到配置文件中。新模型改变了一些必须在“其他”项目的Web中复制的项。配置文件。旧的结构不再适用了。
<add name="MyEntities"
connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;
provider=System.Data.SqlClient;
provider connection string="
data source=Q\DEV15;initial catalog=whatever;
user id=myuserid;password=mypassword;
multipleactiveresultsets=True;
application name=EntityFramework""
providerName="System.Data.EntityClient" />
经过数小时的谷歌搜索和尝试解决建议的解决方案没有一个有效。我在这里列出了几个解决方案。我也注意到了对我有用的方法。(我使用的是EF版本6.1.1,SQL server 2014 -但旧的DB)
重新构建项目并重试。
关闭和打开VS -我不知道这是怎么回事
确保如果你已经把。edmx文件放在一个目录中,确保你在你的连接字符串中包含了目录。例如,我的是在DAL文件夹。所以它看起来是这样的:connectionString="metadata=res://*/ dal . nammodel .csdl|res://*/ dal . nammodel .ssdl|res://*/ dal . nammodel .msl;你可以在解决方案资源管理器中切换显示所有文件,在~/obj/..目录)
...以及更多我尝试过的方法[比如:将EntityFramework版本恢复到后来的版本(不确定)]
对我有用的是:
这篇文章帮助我解决了我的问题。我只是在EDMX文件中将我的ProviderManifestToken=“2012”更改为ProviderManifestToken=“2008”。这样做:
解决方案资源管理器
右键单击文件。edmx
开放与. .
XML编辑器
使用2008更改ProviderManifestToken="XXXX"
我希望这对你有所帮助。
在我的情况下,列出的答案没有一个是有效的,所以我发布了这个。
For my case, building on Visual studio and running it with IIS express worked fine. But when I was deploying using Nant scripts as a stand-alone website was giving errors. I tried all the suggestions above and then realized the DLL that was generated by the nant script was much smaller than the one generated by VS. And then I realized that Nant was unable to find the .csdl, .msl and .ssdl files. So then there are really two ways to solve this issue, one is to copy the needed files after visual studio generates them and include these files in the build deployment. And then in Web.config, specify path as:
"metadata=~/bin/MyDbContext.csdl|~/bin/MyDbContext.ssdl|~/bin/MyDbContext.msl;provider=System.Data.SqlClient;...."
这是假设您已经手动复制文件到您正在运行的网站的bin目录。如果它在不同的目录中,则相应地修改path。
第二种方法是在Nant脚本中执行EdmGen.exe,并生成文件,然后将它们作为资源,如下例所示:
https://github.com/qwer/budget/blob/master/nant.build