是否有可能检索MetadataWorkspace,而不必与数据库的连接? [英] Is it possible to retrieve a MetadataWorkspace without having a connection to a database?

查看:129
本文介绍了是否有可能检索MetadataWorkspace,而不必与数据库的连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写需要穿越实体框架 MetadataWorkspace 对于给定的的DbContext 键入一个测试库。然而,由于这是一个测试库,我宁愿不具有对数据库的连接 - 它引入的依赖,可能无法提供测试环境。

I am writing a test library that needs to traverse the Entity Framework MetadataWorkspace for a given DbContext type. However, as this is a test library I would rather not have a connection to the database - it introduces dependencies that may not be available from the test environment.

当我试图得到一个参考 MetadataWorkspace 像这样:

When I try to get a reference to the MetadataWorkspace like so:

var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;



我收到了的SQLException

类型'System.Data.SqlClient.SqlException'出现在system.data.dll但在用户代码中没有处理的异常

An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code

更多信息:在建立与SQL Server的连接时发生网络相关的或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确,以及SQL Server配置为允许远程连接。 (提供者:SQL网络接口,错误:26 - 错误定位服务器/实例指定)

Additional information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

是否有可能做我想做的,而不一个连接字符串?

Is it possible to do what I want without a connection string?

推荐答案

是的,你可以通过喂食背景虚连接字符串做到这一点。需要注意的是,通常当你调用的DbContext的参数构造函数,它会寻找连接字符串与主应用程序的app.config文件上下文类的名称。如果是这样的话,你不能改变这种行为(就像你没有自己的问题背景下的源代码) - 你将不得不更新与虚拟串发现连接App.config中(可在运行时完成过)。如果你能叫的DbContext构造器的连接字符串,则:

Yes you can do this by feeding context a dummy connection string. Note that usually when you call parameterless constructor of DbContext, it will look for connection string with the name of your context class in app.config file of main application. If that is the case and you cannot change this behavior (like you don't own the source code of context in question) - you will have to update app.config with that dummy conneciton string (can be done in runtime too). If you can call DbContext constructor with connection string, then:

var cs = String.Format("metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\"\"", "TestModel");
using (var ctx = new TestDBEntities(cs)) {
    var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace;
    // no throw here
    Console.WriteLine(metadata);                
}



所以,你只提供重要参数,以获得元数据的工作空间,并提供空连接字符串

So you providing only parameters important to obtain metadata workspace, and providing empty connection string.

更新:更多的思考之后,你不需要使用这种黑客和实例化背景下的所有

UPDATE: after more thought, you don't need to use such hacks and instantiate context at all.

public static MetadataWorkspace GetMetadataWorkspaceOf<T>(string modelName) where T:DbContext {
    return new MetadataWorkspace(new[] { $"res://*/{modelName}.csdl", $"res://*/{modelName}.ssdl", $"res://*/{modelName}.msl" }, new[] {typeof(T).Assembly});
}



在这里,你只需要使用MetadataWorkspace类的构造函数直接,传递路径,目标元数据元素还装配检查。注意,此方法使一些假设:元数据构件被嵌入到资源(通常是这样,但也可以是外部的,或在另一路径嵌入式),需要的一切都在相同的程序集的上下文类本身(可能在理论上有上下文用汇编和实体类在另一个,或东西)。但我希望你的想法

Here you just use constructor of MetadataWorkspace class directly, passing it paths to target metadata elements and also assembly to inspect. Note that this method makes some assumptions: that metadata artifacts are embedded into resources (usually they are, but can be external, or embedded under another paths) and that everything needed is in the same assembly as Context class itself (you might in theory have context in one assembly and entity classes in another, or something). But I hope you get the idea.

UPDATE2:获取的代码优先模型元数据的工作空间是较为复杂的,因为该模型EDMX文件在运行时产生的。在哪里,它是如何产生的实现细节。但是,你仍然可以得到的元数据的工作空间与一些努力:

UPDATE2: to get metadata workspace of code-first model is somewhat more complicated, because edmx file for that model is generated at runtime. Where and how it is generated is implementation detail. However, you can still get metadata workspace with some efforts:

    public static MetadataWorkspace GetMetadataWorkspaceOfCodeFirst<T>() where T : DbContext {
        // require constructor which accepts connection string
        var constructor = typeof (T).GetConstructor(new[] {typeof (string)});
        if (constructor == null)
            throw new Exception("Constructor with one string argument is required.");
        // pass dummy connection string to it. You cannot pass empty one, so use some parameters there
        var ctx = (DbContext) constructor.Invoke(new object[] {"App=EntityFramework"});
        try {                
            var ms = new MemoryStream();
            var writer = new XmlTextWriter(ms, Encoding.UTF8);
            // here is first catch - generate edmx file yourself and save to xml document
            EdmxWriter.WriteEdmx(ctx, writer);
            ms.Seek(0, SeekOrigin.Begin);
            var rawEdmx = XDocument.Load(ms);
            // now we are crude-parsing edmx to get to the elements we need
            var runtime = rawEdmx.Root.Elements().First(c => c.Name.LocalName == "Runtime");                
            var cModel = runtime.Elements().First(c => c.Name.LocalName == "ConceptualModels").Elements().First();
            var sModel = runtime.Elements().First(c => c.Name.LocalName == "StorageModels").Elements().First();
            var mModel = runtime.Elements().First(c => c.Name.LocalName == "Mappings").Elements().First();

            // now we build a list of stuff needed for constructor of MetadataWorkspace
            var cItems = new EdmItemCollection(new[] {XmlReader.Create(new StringReader(cModel.ToString()))});
            var sItems = new StoreItemCollection(new[] {XmlReader.Create(new StringReader(sModel.ToString()))});
            var mItems = new StorageMappingItemCollection(cItems, sItems, new[] {XmlReader.Create(new StringReader(mModel.ToString()))});
            // and done
            return new MetadataWorkspace(() => cItems, () => sItems, () => mItems);
        }
        finally {
            ctx.Dispose();
        }
    }

这篇关于是否有可能检索MetadataWorkspace,而不必与数据库的连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆