EF Core simple logging with In-Memory database - entity-framework-core

I tried EF Core simple logging with SQL Server and Sqlite. It's working fine.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//optionsBuilder.UseSqlServer("Data Source= (localdb)\\MSSQLLocalDB; Initial Catalog=SamuraiAppDataFirstLook");
// optionsBuilder.UseSqlite("Data Source = SamuraiAppDataFirstLook.sqlite");
optionsBuilder.UseInMemoryDatabase(new Guid().ToString());
optionsBuilder.LogTo(logMessage =>
{
Debugger.Break();
Debug.WriteLine(logMessage);
Console.WriteLine(logMessage);
},
new[] {
DbLoggerCategory.Database.Command.Name }, LogLevel.Information
);
optionsBuilder.EnableDetailedErrors();
optionsBuilder.EnableSensitiveDataLogging();
}
But when I tried with an In-Memory database, it's not working.
Is this by design? Or am I missing something?
A full working sample to reproduce the problem is here on github.
The Debugger.Break() here is not hit, if I use the inMemory database here.
But if use SQL Server or Sqlite provider, then it does break at the debugger break as expected.
So what am I missing? Is it that the simple logging is not supported for In-Memory databases?

The inmemory provider is not a relational provider, so does not execute DbCommands. So nothing to log.

Related

Dear sirs I can't get OrderStateMachine to generate the MSSQL database schema

I'm using Masstransit for the first time, and can't make my sag's Persistable. Following the documented saga sample (EF Core): https://masstransit-project.com/usage/sagas/efcore.html
Generating the Initial migration fails, being quite new to both EF and masstransit I'm lost.
Looks like DI can't find the correct DbContextOptions
PM> dotnet ef migrations add InitialCreate -c OrderStateDbContext
Build started...
Build succeeded.
Unable to create an object of type 'OrderStateDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
MassTransit.EntityFrameworkCore v7.1.7
Microsoft.EntityFrameworkCore.SqlServer v5.0.4
Microsoft.EntityFrameworkCore.Design v5.0.4
Code;
collection.AddMassTransit(x =>
{
x.AddSagaStateMachine<OrderStateMachine, OrderState>()
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Pessimistic; // or use Optimistic, which requires RowVersion
r.AddDbContext<DbContext, OrderStateDbContext>((provider, builder) =>
{
builder.UseSqlServer(connectionString, m =>
{
m.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name);
m.MigrationsHistoryTable($"__{nameof(OrderStateDbContext)}");
});
});
});
public class OrderStateDbContext :
SagaDbContext
{
public OrderStateDbContext(DbContextOptions options)
: base(options)
{
}
protected override IEnumerable<ISagaClassMap> Configurations
{
get { yield return new OrderStateMap(); }
}
}
Appreciate any help
Duncan
First, you are reading the old v6 documentation (which was preserved for those on v6). You should be referencing the current documentation.
Second, I don't see any issue with the two types, the context should be available in the assembly. For a working example, look at ForkJoint.
It registers the DbContext separately and uses that DbContext in the saga repository, but it should work either way.

System.InvalidOperationException: Relational-specific methods can only be used when the context is using a relational database provider

System.InvalidOperationException:
Relational-specific methods can only be used when the context is using a relational database provider.
Getting the above mentioned error while using InMemoryDatabase for Test Case?
var msaContextOptions = new DbContextOptionsBuilder<MSA.DAL.MsaDbContext>()
.UseInMemoryDatabase(databaseName: "Get results")
.ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
Comparing with provider string is brittle - what if Microsoft changes to Microsoft.EntityFramework as it moves away from Core!
I would recommend to use
if (!context.Database.IsInMemory())
{
context.Database.Migrate();
}
or
if (context.Database.IsRelational())
{
context.Database.Migrate();
}
we have EF-related code in a separate nuget package that doesn't include Microsoft.EntityFrameworkCore.InMemory, therefore first option doesn't work for us.
As mentioned by other people I found skipping DBMigration is the best option for now.
I am running Database Migration when Database ProviderName is not InMemory.
if (context.Database.ProviderName != "Microsoft.EntityFrameworkCore.InMemory")
{
context.Database.Migrate();
}
In our case, the solution of #hemant-sakta didn't work. The cause for the error was that we set the auto-increment value in one of our database tables on seeding (we seed during migration).
The solution was to skip setting the auto-increment value when in Isolated Mode:
private static void SetAutoIncrementValue(MyContext context)
{
if (HostingEnvironment.IsEnvironment("Isolated")) return;
// auto increment code
}

Manage Transactions on Business Layer

I want to use TransactionScope class in my business layer to manage database operation in data access layer.
Here is my sample code. When i execute it, it tries to enable the dtc. I want to do the operation without enable dtc.
I already checked https://entlib.codeplex.com/discussions/32592 article. It didn't work for me. I read many articles on this subject but none of them really touch enterprise library or i didn't see.
by the way, i am able to use TransactionScope using dotnet sql client and it works pretty well.
what would be the inside of SampleInsert() method?
Thanks,
Business Layer method:
public void SampleInsert()
{
using (TransactionScope scope = new TransactionScope())
{
Sample1DAL dal1 = new Sample1DAL(null);
Sample2DAL dal2 = new Sample2DAL(null);
Sample3DAL dal3 = new Sample3DAL(null);
dal1.SampleInsert();
dal2.SampleInsert();
dal3.SampleInsert();
scope.Complete();
}
}
Data Access Layer method:
//sampleInsert method structurally same for each 3 dal
public void SampleInsert()
{
Database database = DatabaseFactory.CreateDatabase(Utility.DATABASE_INFO); ;
using (DbConnection conn = database.CreateConnection())
{
conn.Open();
DbCommand cmd = database.GetStoredProcCommand("P_TEST_INS", "some value3");
database.ExecuteNonQuery(cmd);
}
}
Hi yes this will enable dtc because you are creating 3 DB connections within one TransactionScope . When more than one DB connection is created within same TransactionScope the local transaction escalate to Distributed Transaction and hence dtc will be enabled to manage Distributed Trnsactions.You will have to do it in a way that only one DB connection is created for entire TransactionScope. I hope this will give you an idea.
After research and waching query analyzer, I changed the SampleInsert() body as follows and it worked. The problem was as ethicallogics mentioned opening new connection each time i access the database.
public void SampleInsert()
{
Database database = DatabaseFactory.CreateDatabase(Utility.DATABASE_INFO);
using (DbCommand cmd = database.GetStoredProcCommand("P_TEST_INS", "some value1"))
{
database.ExecuteNonQuery(cmd);
}
}

Entity Framework 4.1 "Code First" SetInitializer not being called again after Database.Delete

Trying to do some unit testing with EF 4.1 code first. I have my live db (SQL Server) and my unit test DB( Sql CE). After fighting (and losing) with EF, Sql CE 4.0 and Transaction support I decided the simplest way to run my test was to:
Create Db
Run Test
Delete Db
Rinse and repeat
I have my [Setup] and [TearDown] functions:
[SetUp]
public void Init()
{
System.Data.Entity.Database.SetInitializer(new MyTestContextInitializer());
_dbContext = ContainerFactory.Container.GetInstance<IContext>();
_testConnection = _dbContext.ConnectionString;
}
[TearDown]
public void Cleanup()
{
_dbContext.Dispose();
System.Data.Entity.Database.Delete(_testConnection);
}
Issue is that System.Data.Entity.Database.SetInitializer does not call MyTestContextInitializer after the first test.
Hence the 2nd test then fails with:
System.Data.EntityException : The
underlying provider failed on Open.
----> System.Data.SqlServerCe.SqlCeException
: The database file cannot be found.
Check the path to the database
TIA for any pointers
I got around this by calling 'InitializeDatabase' manually. Like so:
[SetUp]
public void Init()
{
var initializer = new MyTestContextInitializer();
System.Data.Entity.Database.SetInitializer(initializer);
_dbContext = ContainerFactory.Container.GetInstance<IContext>();
initializer.InitializeDatabase((MyTestContext)_dbContext);
_testConnection = _dbContext.ConnectionString;
}
[TearDown]
public void Cleanup()
{
System.Data.Entity.Database.Delete(_testConnection);
_dbContext.Dispose();
}
I think it may be a bug with EF 4.1 RC.
It's not a bug, the initializer set with
System.Data.Entity.Database.SetInitializer
is only called when the context is created for the first time in the AppDomain. Hence, since you're running all your tests in a single AppDomain, it's only called when the first test is ran.
It took me almost a day to find out what caused my strange unittest behaviour: the database connection stayed open or the database was not created with a every new test. I searched everywhere for the root of the cause: MSTest (no Admin rights or where working copies of files somehow deleted?), SQL Server Express/CE (login failure?), Unity (objects not disposed?) or Entity Framework (no proper database initialization?). It turned out to be EF. Thanks a lot for the answer!

How do I recreate DB using EF4 code first for test

I'm using Entity Framework 4 Code First in my .net MVC 2.0 project and I'm having hard times to get my DB sync with my Entities. What I want is a page that I can call, as an exemple : /DB/Recreate, that would drop my current DB and recreate an empty one. Currently in my global.asax I have
protected override void OnApplicationStarted()
{
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
I try to switch my database initializer in my action but I'm realy not sure, since it should already been initialized, that I'm using the right approach :
Database.SetInitializer(new AlwaysRecreateDatabase<CorpiqDb>());
var bidon = _session.All<Admin>();
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
bidon = _session.All<Admin>();
I don'y realy know how to do this, thank you for the help!
Ok I found a solution :
var dbContext = new CorpiqDb().Database ;
dbContext.Delete();
dbContext.Initialize();
dbContext.EnsureInitialized();
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
This will drop my database and create a new one that reflect the latest models, I can even seed the database with some data for my test.