使用 SQL CE 的 ABP 样板
ABP Boilerplate using SQL CE
我有一个简单的 ASP.NET 应用程序,它使用 EntityFramework 和一个 SQL 服务器 EF 数据库。
问题是,如果我尝试使用 SQL CE(精简版),我的应用程序服务会在第二次调用存储库时抛出异常并显示错误:
ExecuteReader 需要一个打开且可用的连接。
如果我 return 到 SQL Express 数据库,一切都会成功。
这里是我使用的步骤和代码:
对客户端应用程序 App.config 文件的修改(我只报告更改):
<!-- language: lang-xml -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" .../>
</configSections>
<connectionStrings>
<add name="Default" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=C:\temp\Deeds.sdf" />**
</connectionStrings>
...
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
...
</configuration>
我必须设置 UOW 的隔离级别:
public class DeedsWinFormEFModule : AbpModule {
public override void PreInitialize() {
Configuration.UnitOfWork.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
}
public override void Initialize() {
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
但在我的 ApplicationService 中,此方法在第二次数据库查询时失败
public class DeedImmobileAppService
: DeedsAppServiceBase, IDeedImmobileAppService {
protected readonly IRepository<CfgBase100Repo> _cfgBase100Repo;
protected readonly IRepository<CfgCasa> _cfgCasaRepo;
...
public async Task<IReadOnlyList<DeedEntryDto>> CalculateValuesForEntries(UpdateDefaultEntriesRequest input) {
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
...
return list;
}
}
对存储库的第二次调用 总是 失败 (var tipoCasa = ...
):
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
我也试过把台词倒过来。在这种情况下 var base100 =
失败:
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
我收到的错误是:
Inner Exception 1:
EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
Inner Exception 2:
InvalidOperationException: ExecuteReader requires an open and available Connection. The connection's current state is Closed.
这里是堆栈跟踪:
System.Reflection.TargetInvocationException HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib StackTrace: at
System.RuntimeMethodHandle.InvokeMethod(Object target, Object[]
arguments, Signature sig, Boolean constructor) at
System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj,
Object[] parameters, Object[] arguments) at
System.Delegate.DynamicInvokeImpl(Object[] args) at
System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry
tme) at
System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry
tme) at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m) at
System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&
m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr
hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at
System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr
dwComponentID, Int32 reason, Int32 pvLoopData) at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context) at
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context) at
System.Windows.Forms.Application.Run(Form mainForm) at
GPSoftware.Deeds.WinForm.Program.Main() in
C:\WA\GPse\NotuleNotai\Notule\Deeds.WinForm\Program.cs:line 34
内部异常 1:
EntityCommandExecutionException: An error occurred while executing the
command definition. See the inner exception for details.
内部异常 2:
InvalidOperationException: ExecuteReader requires an open and
available Connection. The connection's current state is Closed.
我不确定这是正确的解决方案,但我通过 将 UOW 标记为非事务性 :
解决了这个问题
[DependsOn(
typeof(DeedsDataModule),
typeof(DeedsApplicationModule))]
public class DeedsWinFormEFModule : AbpModule {
public override void PreInitialize() {
// Configuration.UnitOfWork.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; // <= this is not needed!
Configuration.UnitOfWork.IsTransactional = false; // <= solution!
}
public override void Initialize() {
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
更新
这是正确的解决方案:EF 不支持 SQL CE 事务,因为 TransactionScope 在使用 SQL CE 时会导致升级到分布式事务使用 Code First 和 SQL CE 不支持分布式事务。
我有一个简单的 ASP.NET 应用程序,它使用 EntityFramework 和一个 SQL 服务器 EF 数据库。
问题是,如果我尝试使用 SQL CE(精简版),我的应用程序服务会在第二次调用存储库时抛出异常并显示错误:
ExecuteReader 需要一个打开且可用的连接。
如果我 return 到 SQL Express 数据库,一切都会成功。
这里是我使用的步骤和代码:
对客户端应用程序 App.config 文件的修改(我只报告更改):
<!-- language: lang-xml -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" .../>
</configSections>
<connectionStrings>
<add name="Default" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=C:\temp\Deeds.sdf" />**
</connectionStrings>
...
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
...
</configuration>
我必须设置 UOW 的隔离级别:
public class DeedsWinFormEFModule : AbpModule {
public override void PreInitialize() {
Configuration.UnitOfWork.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
}
public override void Initialize() {
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
但在我的 ApplicationService 中,此方法在第二次数据库查询时失败
public class DeedImmobileAppService
: DeedsAppServiceBase, IDeedImmobileAppService {
protected readonly IRepository<CfgBase100Repo> _cfgBase100Repo;
protected readonly IRepository<CfgCasa> _cfgCasaRepo;
...
public async Task<IReadOnlyList<DeedEntryDto>> CalculateValuesForEntries(UpdateDefaultEntriesRequest input) {
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
...
return list;
}
}
对存储库的第二次调用 总是 失败 (var tipoCasa = ...
):
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
我也试过把台词倒过来。在这种情况下 var base100 =
失败:
var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
我收到的错误是:
Inner Exception 1:
EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
Inner Exception 2:
InvalidOperationException: ExecuteReader requires an open and available Connection. The connection's current state is Closed.
这里是堆栈跟踪:
System.Reflection.TargetInvocationException HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib StackTrace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Delegate.DynamicInvokeImpl(Object[] args) at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at GPSoftware.Deeds.WinForm.Program.Main() in C:\WA\GPse\NotuleNotai\Notule\Deeds.WinForm\Program.cs:line 34
内部异常 1:
EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
内部异常 2:
InvalidOperationException: ExecuteReader requires an open and available Connection. The connection's current state is Closed.
我不确定这是正确的解决方案,但我通过 将 UOW 标记为非事务性 :
解决了这个问题[DependsOn(
typeof(DeedsDataModule),
typeof(DeedsApplicationModule))]
public class DeedsWinFormEFModule : AbpModule {
public override void PreInitialize() {
// Configuration.UnitOfWork.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; // <= this is not needed!
Configuration.UnitOfWork.IsTransactional = false; // <= solution!
}
public override void Initialize() {
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
更新
这是正确的解决方案:EF 不支持 SQL CE 事务,因为 TransactionScope 在使用 SQL CE 时会导致升级到分布式事务使用 Code First 和 SQL CE 不支持分布式事务。