In DbContext to log the queries Log action is being used. Where is it being invoked under the hood?
public ApplicationDbContext(): base("DefaultConnection")
{
Database.Log = sql => Debug.Write(sql);
}
Related
I am working on a project that gets connection strings for Entity Framework from environment variables, like this:
public class SomeTests {
[Fact]
public async void TestSomething() {
string connectionString = Environment.GetEnvironmentVariable("APP_CONN_STR");
var appContextOptionsBuilder = new DbContextOptionsBuilder<AppDataContext>();
appContextOptionsBuilder.UseMySql(connectionString); // hardcoded mysql
AppDataContext context = new AppDataContext(appContextOptionsBuilder.Options);
Assert.Equal(context.Country.Count(), 0);
}
}
....
public partial class AppDataContext : DbContext, IAppDataContext
{
public AppDataContext(DbContextOptions options) : base(options)
{
}
public virtual DbSet<Country> Country { get; set; }
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Country>(entity =>
{
entity.ToTable("country");
...
});
...
}
}
The code above is a bootstrapper code for some automated integration testing. Historically every developer is using the same old database instance on the network without a problem. I am trying to make these tests run in an isolated environment, so I have set up an empty new mysql database (using docker to make it reproducible), and let Entity Framework to populate it with a schema.
The problem is, when I create an empty database in this mysql instance and give a connection string to that database, then I am getting table not found errors:
connection str: Server=127.0.0.1;Port=3306;Database=app_mysql_db;Uid=root;Pwd=****;
error: MySql.Data.MySqlClient.MySqlException : Table 'app_mysql_db.country' doesn't exist
I found out that EF will not create tables in existing databases, it will only populate a database with tables if EF itself created it. This is the default behavior of EF.
So I tried to remove the database name from the connection string:
connection str: Server=127.0.0.1;Port=3306;Uid=root;Pwd=****;
error: MySql.Data.MySqlClient.MySqlException : No database selected
So how do I let Entity Framework in Code First mode to create my tables?
I am using entity framework 6.0, and here is how I set the connection timeout:
DbContext cc = new DbContext("Data Source=VLT180;Initial Catalog=VISTAIT;Persist Security Info=True;User ID=XXXXXXXX;Password=XXXXX;Connect Timeout=6");
cc.Database.ExecuteSqlCommand("select * from table1");
but this does not work, when I disconnect my network, the code will hang at the "ExecuteSqlCommand" method infinitely. if I reconnect my network, it works correctly as expected.
I am using the latest entity framework: 6.1.3
Is there any clue?
Your Context must look like
public class Context : DbContext
{
public Context(string connectionString) : base(connectionString)
{
}
public DbSet<Quote> Quote { get; set; }
}
Then you can execute raw sql as follows
using (var context = new Context())
{
var quotes = context.Quote.SqlQuery("SELECT * FROM dbo.Quote").ToList();
}
You execute sql on the dbset Quote.
I'm working with EF 6 and have the repository class such this:
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
public EfRepository(DbContext context)
{
_context = context;
}
....
public void Delete(IEnumerable<T> entities)
{
// skip checks
using (var transaction = _context.Database.BeginTransaction())
{
try
{
_context.Set<T>().RemoveRange(entities);
_context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}
In my controller I have repository instance IRepository<Connection> _repository than binded with Autofac to EfRepository class.
Then I remove multiple items (and everything works fine!):
IEnumerable<Connection> connections = // get some connections;
_repository.Delete(connections); // everything fine - records was removed
But when I open my site with installed MiniProfiler it shows me duplicate sql-query warning:
My question is why I use transactions but still has duplicate sql warning?
Thank you.
This is because Entity Framework currently sends one query per item to be deleted. It does not batch them all into one query. So MiniProfiler is correctly reporting on what is happening - duplicate delete queries (with exception of the param value) are being submitted.
What is your transaction.Commit() doing? Maybe you can add the code of this method to your question.
I am also deleting entites from my database but more like this:
public virtual void Delete(TEntity entityToDelete)
{
if (Context.Entry(entityToDelete).State == EntityState.Detached)
{
DBSet.Attach(entityToDelete);
}
DBSet.Remove(entityToDelete);
}
I think there are no differences between Remove and RemoveRange, but maybe you should check the state first?
When I execute my web app and try to save data into databse, this exception happens :
Model compatibility cannot be checked because the database does not
contain model metadata. Model compatibility can only be checked for
databases created using Code First or Code First Migrations.
I try lot of issue for resolve this problem , but it persist yet !!
Using migrations isn't really necessary if you're developing on your local machine. You can just set the database Initializer to drop the database always, run some code that interacts with the database, and then you'll see that the database will be recreated and the error will be gone.
Should work, that's how I do it.
delete the database manually, then restart the project with:
public class DbDataContext : DbContext
{
public IDbSet<FlightType> FlightTypes { get; set; }
public DbDataContext()
{
//Validates if database Exists or if is CompatibleWithModel
//Using when Databes is productive - use code first migrations for db changes in this case
//Database.SetInitializer(new ValidateDatabase<DbDataContext>());
//Custom Initializer - crates databse with required entries
//Using while developing
Database.SetInitializer<DbDataContext>(new DatabaseInitializer<DbDataContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
DatabaseInitializer:
public class DatabaseInitializer<T> : DropCreateDatabaseIfModelChanges<DbDataContext>
{
protected override void Seed(DbDataContext dbDataContext)
{
dbDataContext.FlightTypes.Add(new FlightType { FlightTypeNummer = "axd", Name = "AXD_LX", IsDefault = true });
base.Seed(dbDataContext);
}
}
ValidateDatabase:
public class ValidateDatabase<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext
{
public void InitializeDatabase(TContext context)
{
if (!context.Database.Exists())
{
throw new InvalidOperationException("Database does not exist");
}
if (!context.Database.CompatibleWithModel(true))
{
throw new InvalidOperationException("The database is not compatible with the entity model.");
}
}
}
Are you trying to use Code-First Migrations? If so, have you run the following command in the Package Manager Console?
PM> Enable-Migrations
I am creating an Entity Framework Code-First model to execute ad-hoc queries against a SQL Server database. I am not including any tables/views from the "dbo" schema in my EF model; instead I am only including tables/views from the "model" schema in my database. I do have duplicate names of objects in my database that are separated only by schema (e.g. "dbo.Child" and "model.Child").
Is there one line I can specify in the DbContext that will say in essence "map all entities in this context to the 'model' schema"? I know that I can map each entity to the proper schema (see below), but I'd like to avoid listing out every entity in my database again.
This is what I know I can do:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Child>().ToTable("Child", "model");
modelBuilder.Entity<Referral>().ToTable("Referral", "model");
// 100 lines later...
modelBuilder.Entity<Exit>().ToTable("Exit", "model");
}
This is what I'd like to do:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new MapAllEntitiesToSchemaConvention("model"));
}
I couldn't find anyway to do this out of the box in EF 4.2, but I needed all my entities to be in a different schema so I hacked this up in an attempt to keep things DRYer. It uses the same underlying pluralization engine as EF, and the overrides are there incase entities need to specify the table name.
A reference to System.Data.Entity.Design is needed.
public class BaseConfiguration<TEntityType> : EntityTypeConfiguration<TEntityType> where TEntityType : class
{
private readonly static PluralizationService ps = PluralizationService.CreateService(new CultureInfo("en-US"));
public BaseConfiguration() : this(ps.Pluralize(typeof(TEntityType).Name)) { }
public BaseConfiguration(string tableName) : this(tableName, MyContext.Schema) { }
public BaseConfiguration(string tableName, string schemaName)
{
ToTable(tableName, schemaName);
}
}
I define the schema name via a constant string in MyContext, ie:
public class MyContext : DbContext
{
public const string Schema = "my";
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SnapshotConfiguration());
}
}
And my entities configurations look like:
public class SnapshotConfiguration : BaseConfiguration<Snapshot>
{
...
}
Caveat: I still need configuration's for each entity I want in the correct schema - but the jist of it could be adopted elsewhere.