ABP Boilerplate using SQL CE

0

I have a simple ASP.NET application using EntityFramework and a SQL Server EF DB.

The problem is that if I try to use SQL CE (Compact Edition), my application services throws an exception on the second call to the repository with the error:

ExecuteReader requires an open and available Connection.

All works successfully if I return to a SQL Express database.

Here the step and code I used:

Modification to the client application App.config file (I report only changes):

<!-- 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>

They I had to set the isolation level of the UOW:

public class DeedsWinFormEFModule : AbpModule {

    public override void PreInitialize() {
        Configuration.UnitOfWork.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
    }

    public override void Initialize() {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

But in my ApplicationService this method fails on the second DB query

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;
    }
}

The second call to the repository always fails (var tipoCasa = ...):

    var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));
    var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);

I also tried to invert the lines. In this case var base100 = fails:

    var tipoCasa = await _cfgCasaRepo.FirstOrDefaultAsync(input.HouseTypeId);
    var base100 = await _cfgBase100Repo.FirstOrDefaultAsync(cfg => (cfg.MinDeedRange <= input.DeedValue) && (input.DeedValue < cfg.MaxDeedRange));

The error I receive is:

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.

Here the stack trace:

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

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.

sql-server-ce
aspnetboilerplate
asp.net-boilerplate
asked on Stack Overflow Feb 20, 2018 by Gianpiero • edited Feb 21, 2018 by Gianpiero

1 Answer

1

I am not sure it is the right solution, but I solved the issue by marking the UOW not transactional:

[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());
    }
}

UPDATE

This is the correct solution: EF doesn't support SQL CE transactions because TransactionScope can cause escalation to a distributed transaction when using SQL CE with Code First and SQL CE does not support distributed transactions.

answered on Stack Overflow Feb 20, 2018 by Gianpiero • edited Mar 15, 2018 by Gianpiero

User contributions licensed under CC BY-SA 3.0