是否可以构建一个包含实体框架(Core 或 EF6)的 PowerShell cmdlet 以访问 SQL Server 数据库?
我多年来一直在用 C# 编写 cmdlet,但在过去的 coupla 日子里,由于似乎是程序集版本冲突,我在尝试在项目中使用实体框架时经历了一场噩梦。
项目有三个库:
-
MyProject.Commands.dll
- 要加载的cmdlet
-
MyProject.Lib.dll
- cmdlet 使用的通用库代码
-
MyProject.EF.dll
- 仅实体框架内容。
EF 是独立的,因为我使用数据库优先的方法(我必须对现有系统进行逆向工程),因此各种.cs
从数据库构建的模型文件位于单独的单元中,因此请保持它们的整齐。
我正在 Windows 10 上构建所有这些,并且该项目只需要在这台机器。它正在与 Azure 云中的 SQL 数据库进行通信。
第一次尝试:VS 2017 / .Net Framework 4.7.1
使用 nuget 添加所需的包后,一切都构建得很好,但是使用Import-Module
on MyProject.Commands.dll
让我明白:
System.IO.FileNotFoundException: Could not load file or assembly \
'System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' \
or one of its dependencies. The system cannot find the file specified.
打开某种绑定调试日志记录后,
=== Pre-bind state information ===
LOG: DisplayName = System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
(Fully-specified)
LOG: Appbase = file:///C:/Windows/System32/WindowsPowerShell/v1.0/
LOG: Initial PrivatePath = NULL
Calling assembly : Microsoft.EntityFrameworkCore.Relational, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60.
我一直没能找到确切的版本System.ComponentModel.Annotation
,但互联网上充斥着关于同一问题的报道。我用DLL中的AssemblyResolver尝试了各种方法,各种框架的不同版本,最终一无所获。
最终我找到了这个页面https://learn.microsoft.com/en-us/ef/core/platforms/ https://learn.microsoft.com/en-us/ef/core/platforms/这表明任何 .NET 框架版本(在 .NET Core 上)都不支持 EF Core 3.x,但是几天前的这篇博文https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-3-1-and-entity-framework-6-4/ https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-3-1-and-entity-framework-6-4/表明它现在已经得到支持了。
上面是一个粗略的重述,因为它是很久以前(昨晚深夜)在我执行 B 计划之前的事情。这太令人抓狂了。
B 计划:.NET Core 3.1 上的 EF Core
无论如何,我认为 EF Core 可能是未来更好的方向,因此我购买了 VS 2019,并将整个项目重新定位到 .NET Core 3.1 上的 EF Core 3.1。这是我第一次涉足 .NET Core。
花了一点时间才整理出依赖关系(包括交换System.Management.Automation
for Microsoft.PowerShell.SDK
),但最终一切都建成了。安装 Powershell 6 后,我现在看到的是:
VERBOSE: Loading module from path 'D:\Dev\MyProject\MyProject.Commands\bin\Debug\netcoreapp3.1\MyProject.Commands.dll'.
Import-Module : Could not load file or assembly 'System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f
7f11d50a3a'. The system cannot find the file specified.
惊人的!!
现在找不到4.2.2.0版本System.Runtime
,我真的很茫然。
在每个项目的构建区域内bin\Debug\netcoreapp3.1\
目录是一个*.deps.json
列出各种依赖关系的文件,但每个引用System.Runtime
适用于 4.3.0 版。
我尝试过 Process Monitor,这是用于查看程序集、探索 GAC 的各种工具。纳芬。
使其成为一个应用程序
保持库不变,我将主要逻辑封装到控制台应用程序中,并将其编译为.EXE
.
第一次就成功了。
这可能吗?
构建控制台应用程序如此顺利这一事实表明,尝试在 PowerShell 中完成所有这些工作很可能是无法解决的。
独立应用程序可以控制自己的依赖项,但是构建必须托管在另一个程序(powershell)内的 DLL 意味着我们必须与its依赖关系。
让我印象深刻的是might可以仔细分析现有的pwsh.exe
(即 Powershell 6)并找到其确切的依赖项集,然后查找恰好与该集匹配的 EF Core 版本。这看起来前景并不乐观,但很可能很脆弱。
作为一个数据点,此代码的早期版本在通过直接 SQL 调用与 SQL 服务器通信时工作正常,因此所有数据库访问包袱不足以破坏 cmdlet 兼容性。但添加 EF core 似乎可以。
我讨厌我的生活。我注定了吗?
EDIT需要明确的是,我并没有尝试在 PowerShell 中使用实体框架script,我不确定我是否愿意。它在 C# DLL 中使用 EF,以编程方式完成与数据库对话的所有繁重工作
我已经有了相当合理的直接 SQL 调用(同样是在 C# 中),效果非常好,但我有几十个表需要进行逆向工程,让 EF 通过构建模型和所有易于访问的方式为我完成此任务非常有帮助代码。
foreach (var item in DbContext.Employee
.Where(x => x.Salary > 1000.00)
.OrderBy(x => x.EmployeeId))
{
do something
}
实体框架包构建了Employee
类来自数据库中的定义(尽管您也可以使用代码优先方法),而上面的代码实际上是我必须编写的唯一代码。
我很早就想在 PowerShell cmdlet 中使用 EF,但一直没能实现。
关于实体框架的一个很好的路过读物:https://learn.microsoft.com/en-us/ef/core/ https://learn.microsoft.com/en-us/ef/core/
EDIT今天晚上,我发现我一直在为 .NET Core 而不是 .NET Standard(这又与原始 .NET Framework 不同)构建代码,这在很大程度上解释了为什么无法正确加载。
.NET Core 似乎是一个可移植的子集,我只是因为我不知道的不同而迷失在杂草中。另外:“Core”似乎超载(例如“Entity Framework Core”可以在“.Net Standard”上运行良好)。啊。
我仍然无法让它作为 cmdlet 正常工作和运行,但从好的方面来说,我确实又多花了几个小时。
对此可能没有好的解决方案。
EDIT(6/2020) 今天早上我发现六个月前打开的程序集绑定日志记录填满了我的硬盘C:\WINDOWS\SysWOW64\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\IE
目录与千兆字节HTM 文件。哎呀。
这个帖子 https://stackoverflow.com/questions/255669/how-to-enable-assembly-bind-failure-logging-fusion-in-net包括有关如何通过注册表启用/禁用此功能的说明。