How should I create secondary DbContext using ContextProvider.EntityConnection? - entity-framework

I'm using breeze with Code First EF. My production DbContext has IDatabaseInitializer that throws an exception if !context.Database.CompatibleWithModel(true). If I create a context like suggested in the documentation database compatibility cannot be checked.
// The following line will throw NotSupportedException.
// Unable to verify the compatibility of the model because
// the DbContext instance was not created using Code First patterns.
var context2 = new MyDbContext(EntityConnection, false); // create a DbContext using the existing connection
How should I instantiate DbContexts providing ContextProvider's EntityConnection?

During SaveChanges, Breeze's EFContextProvider creates a DbContext instance using the default constructor. This happens prior to BeforeSaveEntity() and BeforeSaveEntities(). So you can rely on that first DbContext instance to check compatibility before your second DbContext instance is created.
In your DbContext, set the database initializer only in the default constructor. In the constructor that takes a DbConnection, set the initializer to null:
public MyDbContext() : base()
{
Database.SetInitializer(new CompatibilityCheckingInitializer<MyDbContext>);
}
public MyDbContext(DbConnection connection) : base(connection, false)
{
Database.SetInitializer(null);
}
This way, you can re-use the database connection on your second DbContext, but still have the initializer working on your first.
Naturally, you are still free to create DbContexts using any constructor you want, as you would have prior to Breeze 1.4. Using the EntityConnection property in your constructor is suggested as a way to help you conserve database connections.

Related

Getting user information in DbContext

I am attempting to use EF migrations to build/seed my database but my DbContext is causing an error when I use the update-database command.
The DbContext I have implemented has two constructors: one accepts no arguments and the other accepts an IUserContext interface. The IUserContext interface returns a username as a string. The IUserContext is used in the SaveChanges() method for setting user-related audit fields (ex. CreatedBy, UpdatedBy) common to all of my entities. Depending on the implementation of the IUserContext interface, the username may be retrieved from a HttpContext (in a mvc app), WindowsIdentity (in a console app), etc.
If a user attempts to call SaveChanges on the DbContext and the IUserContext is not set, it throws an exception. Basically, I do not want changes saved in the DbContext if a username cannot be provided by the IUserContext interface for purposes of recording who is making the modifications. If the DbContext is being used just for querying, using the no-args constructor isn't an issue since IUserContext is only used during SaveChanges.
When I attempt to use the update-database command, the DbMigrationsConfiguration is given an instance of the DbContext instantiated using the no-args constructor. Therefore, it throws an exception when it tries to invoke the DbContext's SaveChanges after the Seed() method.
Question: How do I pass an IUserContext to my DbContext so the update-database command will not fail and, more importantly, be able to set the appropriate entity fields to the name of the user seeding the changes? Is there some form of DI or other customization I can perform in the DbMigrationsConfiguration? Should I simply add an IUserContext accessor method to the DbContext so the IUserContext can be set outside of the constructor?
Maybe I should be asking a larger question: What is the best (most generic?) way of relaying user information to a DbContext for the purposes of recording who is making modifications? I gave some thought about moving this logic to the business layer of my application but it seems so convenient to encapsulate it in the SaveChanges of the DbContext (even more so when change tracking is enabled) .
We have a similar situation where we record modified user in SaveChanges() override. What we ended up doing was creating a BaseWrapper and use IoC to fill it. The second part is creating a MigrationsContextFactory that migrations will use to create the context. This class lives in the same folder as our ApplicationDbContext.
using System.Data.Entity.Infrastructure;
namespace MyApp.Data
{
public class MigrationsContextFactory : IDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext Create()
{
return new ApplicationDbContext(new HttpContextBaseWrapper());
}
}
}
public class HttpContextBaseWrapper : IHttpContextBaseWrapper
{
public string UserName
{
get
{
if (HttpContext.Current == null || HttpContext.Current.User == null)
return string.Empty;
return HttpContext.Current.User.Identity.Name;
}
}
}
https://marazt.wordpress.com/2015/01/09/entity-framework-dbcontext-idbcontextfactory-and-codefirst-migration-problem/

Is DBContext added automatically with EF 6 or must it be added manuall?

New to EF. Following along with DBContext by Lerman/Miller.
When I start a new project, adding EF6 (Database First), the DBContext seems to be added as a default (ie I don't have to add the DBContext separately with T4). Also, for Lazy Loading, the "virtual" needed in the class definitions also seems to be there by default (I don't have to add it like in the book). Is this what is expected?
When you use Database First approach and use EF x DbContext Generator it creates the DbContext for you automatically and set the navigation properties, virtual. If you want to disable lazy loading you can simply use following code
public class MyContext : DbContext
{
public MyContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Most probably the books you are reading are for code first development. If you use database first(especially with the designer) you don't need to make changes.

Adding DbContext into existing .net 4 application

I have existing .net 4 application which is based on object context.
Now I'm adding DbContext in to existing application by inheriting DbContext and call constructor method and pass the existing object context. i.e.
public class DemoModelEntitiesDbContext : DbContext
{
public DemoModelEntitiesDbContext():base(new DemoModelEntities(), dbContextOwnsObjectContext:true)
{
}
public DbSet<ELMAH_Error> ELMAH_Error { get; set; }
}
Than When I call,
using (DemoModelEntitiesDbContext context = new DemoModelEntitiesDbContext())
{
foreach (ELMAH_Error entity in context.ELMAH_Error.ToList())
{
Console.WriteLine(entity.ID);
}
}
I am getting following error message,
"The type 'ObjectContextDemo.ELMAH_Error' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject."
I checked my existing entities are inheriting from EntityObject.
How to add DbContext in to existing application and not changing existing code?
You could cast to object context but then you gain nothing from DbContext if you 100% stick with existing code. but Ive done that with POCOs, not EntityObjects and can't confirm that it would work with entityobjects.
Otherwise it's not possible to do that without changes. DbContext does not support EntityObject. DbContext is designed for POCOs. Plus there are other code differences between DbContext and ObjectContext. You'd have to change even if you were already using POCOs. If you are using the EF designer, you'd have to start by using a different code gen template (ef5 DbContext template). But that will result in very different classes and plenty of changes to your EF calls in your app.

Entity Framework 5.0 Repository with dynamic DbContext

As it says on the tin, is it possible to create an instance of a DbContext suitable for use as an Entity Framework 5.0 POCO context where the properies that are normally declared as
public DbSet<T> Entities { get; set; }
aren't set/known until runtime?
I'd like to make a repository that has methods like
public TEntity Find<TEntity>(object key) where TEntity : class
{
return _context.Set<TEntity>().Find(key);
}
public void Update<TEntity>(TEntity entity) where TEntity : class
{
if (_context.Entry(entity).State == EntityState.Detached) //entity is detached
_context.Set<TEntity>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
.... etc
And then use them like:
Widget w = repository.Find<Widget>(123);
repository.SaveChanges();
This is trivial if the repository's context is set to a class that contains a DbSet<Widget> Widgets, but can it be done such that the entity types that I plan to use won't be know until runtime OR possibly not until I actually USE them? So that if I have a new class Foo, I can immediately query my repository to .Find<Foo>(123) without having to first add a DbSet<Foo> Foos to my DbContext class?
I think this should be possible because there's nothing special about the poco classes or the DbContext instance which holds references to them.
You don't need DbSet<Foo> Foos property in your context. That is just one way to tell context about existence of the Foo entity. There are multiple ways how context discovers mapped entities:
By explicit DbSet<T> properties
By navigation properties in already discovered entities
By specifying mapping in DbModelBuilder
Overriding OnModelCreated in your context type
Creating DbModelBuilder manually, building it and compiling it into DbCompiledModel which can be passed to DbContext constructor
By declaring EntityTypeConfiguration<T> for each entity and adding it to DbModelBuilder (either in OnModelCreated or in manually created DbModelBuilder).
The last option can be used to discover all required entities at application startup (for example by searching assemblies for all entity configuration classes and registering them to model builder) but it is still not fully dynamic solution. Compiled model is normally constructed only once per application run when the context is used for the first time. Without replacing the compiled model you cannot add or remove mapped entity types to the context.

Code First - persisting an object without specialized DbContext

Code First is a terrific feature. But I could not figure out how to persist an object without creating a specialized DbContext first. Is it possible at all? I'd like to see something along these lines:
var dbConn = new SqlCeConnection("Data Source=Test.sdf");
using (var db = new DbContext(dbConn, true))
{
var cmp = new Company { CompanyName = "Microsoft" };
db.Set(typeof(Company)).Add(cmp);
var recordsAffected = db.SaveChanges();
Console.WriteLine(
"Saved {0} entities to the database, press any key to exit.",
recordsAffected);
Console.ReadKey();
}
Is it possible to dynamically register a class for model creation? There must be a way!
No, as I know there is not any possibility to create DbContext without any information about mapping. Specialized context with predefined DbSets is necessary to define mappings and database initialization. You can probably use base DbContext only if you provide informations about mapping through its constructor by passing DbCompiledModel created manually before using DbContext but I haven't tried this yet.
The problem is that DbSets and overriden OnModelCreating are used to infer needed mapping. If you don't have DbSets or OnModelCreating defined DbContext can't infer and cache mapping. Mapping metadata are created and compiled only once for each context type (until application restarts). This operation is considered as very slow. If you don't have specific context type EF can't probably infer mapping and even if it can it will probably need to create and compile metadata for each instance of the context (like for anonymous types).
If you use DbCompiledModel created manually it will be your responsibility to reuse it.