Is there a way I can use hosting env variable to decide which seed data to load? I DI Ihostingenvironment in Dbcontext but doesnt work. Is there any other way?
One way I think is by looking into connectionstring and manually checking if dev/QA exists but thought if there is a better way to do it?
You can create a separate class to use as a singleton.
public class DbOptions
{
public bool UseDefaultSeed { get; set; }
}
In your services add it as:
if (env.EnvironmentName == "")
services.AddSingleton(new DbOptions {
UseDefaultSeed = true
});
You can now inject DbOptions in your DbContext.
Related
I would like to implement nlog to each action to add an element.
So when I do myContext.Society.Add(), I would like to log something.
I create a class DbSetExtension and modify the context StockContext to use DbSetExtension<T> instead DbSet.
public class DbSetExtension<T> : DbSet<T> where T : class
{
public override T Add(T entity)
{
LoggerInit.Current().Trace("Add Done");
return base.Add(entity);
}
}
When i launch the programm, I notice when I access to myContext.Society.Add.
Society is null. So I think I miss something with my class DbSetExtension but I don't find.
public class StockContext : DbContext
{
public StockContext()
: base("StockContext")
{
}
public DbSet<HistoricalDatas> HistoricalDatas { get; set; }
public DbSet<Society> Society { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Do you have any idea,
Regards,
Alex
[UPDATE]
Code allows to add.
If I replace DbSetExtension by DbSet, the same code works.
So my assumption is I miss something when I inherit from DbSet.
public bool SetSymbols()
{
CsvTools csvThreat = new CsvTools();
List<Eoddata> currentEnum =
csvThreat.ExtractData<Eoddata>(ConfigurationManager.GetString("FilePathQuotes", ""));
currentEnum.ForEach(
c =>
{
//LoggerInit.Current().Trace("Add Done");
Sc.Society.Add(
new Society()
{
RealName = c.Description,
Symbol = String.Format("{0}.PA", c.Symbol),
IsFind = !String.IsNullOrEmpty(c.Description)
});
});
if (Sc.SaveChanges() > 0)
return true;
return false;
}
In my opinion you took totally wrong direction. DbContext is made to work with DbSet and not DbSetExtension class. It is able to instantiate objects of type DbSet and not your own type. This is basically why you get this exception. Reparing it would require probably hacking EF internals and I fear that this problem will be just a beginning for you. Instead I would recommend you to use general way of logging with EF with use of interceptor classes. Here this is explained in details at the end of article Logging and Intercepting Database Operations. Generally this approach would be much more advantageous for you. Why? Because DbContext is just man-in-the-middle in communication with db. In logs you generally cares about what happens to db and its data. Calling Add method on DbSet may not have any effect at all if SaveChanges won't be called lated on. On contrary query interceptors lets you log strictly only interaction with db. Basing on query sent to db you may distinguish what is going on.
But if you instist on your approach I would recommend you using extension methods instead of deriving from DbSet:
public static class DbSetExtensions
{
public static T LoggingAdd<T>(this DbSet<T> dbSet, T entity)
{
LoggerInit.Current().Trace("Add Done");
return dbSet.Add(entity);
}
}
and call it like this:
context.Stock.LoggingAdd(entity);
Have anyone been successful in attaching an IoC with OWIN ASP.NET Identity to share the same DbContext as the WebApi (or MVC) application?
I would like that if ASP.Net identity loads the user, it loads in the same dbcontext as used in the rest of the application.
(using AutoFac as IoC - but wouldn't mind an example with other container)
Edit:
06/Jan/2014: Just to be a bit more specific, when the ASP.Net identity attempts to use a DbContext it needs to be the same DbContext instance as the rest of the application. Otherwise it will create two instances of the same DbContext. I am already using the .PerHttpApiRequest() extension.
The problem I found is that when setting up OWIN classes I couldn't find a way to:
1) attach the container to the OWIN pipeline;
2) tell OWIN to resolve the classes it needs using that container so it can share the same scope (i.e. OAUthServerOptions or any other that may contain other dependencies)
Having said that, how can you setup the ASP.Net Identity resolving the two points above?
EDIT: added instantiating the OWIN pipeline as per comment.
As the IdentityDbContext used by ASP.NET Identity inherits from DbContext, you can simply create your own implementation inheriting from IdentityDbContext like so
public class ApplicationContext : IdentityDbContext<ApplicationUser>
{
//additional DbSets
public DbSet<OtherEntity> OtherEntities { get; set; }
}
public class ApplicationUser : IdentityUser
{
//any custom properties you want for your user.
}
public class OtherEntity
{
[Key]
public int Id { get; set; }
}
now as far as using IoC, from a unity perspective, I register an instance of the UserStore like so
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(typeof(ApplicationContext)));
}
then create a wrapper around the user manager
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store)
{
}
}
and inject that wherever I need a user manager.
As for the OWIN pipeline, you need to instantiate the OAuthAuthorizationProvider through your container, like so.
container.RegisterType<IOAuthAuthorizationServerProvider, ApplicationOAuthProvider>(new InjectionConstructor("self", typeof(ApplicationUserManager)));
then for example in WebApi, you need to simply get the instance from the container in startup.
static Startup()
{
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = (IOAuthAuthorizationServerProvider)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IOAuthAuthorizationServerProvider)),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(5),
AllowInsecureHttp = true,
RefreshTokenProvider = new SimpleRefreshTokenProvider()
};
}
My question is the same as this one
However, I don't really see a solution there. Lets say I have a simple model with two POCOs, Country and State.
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
public class State
{
public string Code { get; set; }
public string Name { get; set; }
public virtual Country Country { get; set; }
}
When I use the repository to .GetStateByCode(myCode), it retrieves a dynamic proxy object. I want to send that over the wire using a WCF service to my client. The dynamic proxy is not a know type so it fails.
Here are my alternatives. I can set ProxyCreationEnabled to false on the context and then my .GetStateByCode(myCode) gives me a POCO which is great. However, the navigation property in the POCO to Country is then NULL (not great).
Should I new up a state POCO and manually populate and return that from the dynamic proxy that is returned from the repository? Should I try to use AutoMapper to map the dynamic proxy objects to POCOs? Is there something I'm totally missing here?
I think the answer from Ladislav Mrnka is clear. The Warnings Still apply. Even with this idea below. Becareful what gets picked Up. He just didnt include , if you want to proceed how to easily get data from Object a to object B. That is question at hand really.
Sample solution
See nuget package ValueInjecter (not the only tool that can do this... but very easy to use)
it allows easy copying of One object to another especially with the same properties and types.
( remember the lazy loading / navigation implications).
So vanilla option is :
var PocoObject = new Poco();
PocoObject.InjectFrom(DynamicProxy); // copy contents of DynamicProxy to PocoObject
but check the default behaviour and consider a custom rule
var PocoObject = new Poco();
PocoObject.InjectFrom<CopyRule>(DynamicProxy);
public class CopyRule : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
bool usePropertry; // return if the property it be included in inject process
usePropertry = c.SourceProp.Name == "Id"; // just an example
//or
// usePropertry = c.SourceProp.Type... == "???"
return usePropertry;
}
}
Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?
public interface ICustomDbContext : IDbContext
{
// add entity set properties to existing set of methods in IDbContext
IDbSet<SomeEntity> SomeEntities { get; }
}
I see this IDbContext:
See this link And then you make a new partial class for your Entities Context With That interface.
public partial class YourModelEntities : DbContext, IDbContext
EDITED:
I edited this post, This Works for me.
My Context
namespace dao
{
public interface ContextI : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
int SaveChanges();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
DbEntityEntry Entry(object entity);
string ConnectionString { get; set; }
bool AutoDetectChangedEnabled { get; set; }
void ExecuteSqlCommand(string p, params object[] o);
void ExecuteSqlCommand(string p);
}
}
YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI
NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.
namespace dao
{
public partial class YourModelEntities :DbContext, ContextI
{
public string ConnectionString
{
get
{
return this.Database.Connection.ConnectionString;
}
set
{
this.Database.Connection.ConnectionString = value;
}
}
bool AutoDetectChangedEnabled
{
get
{
return true;
}
set
{
throw new NotImplementedException();
}
}
public void ExecuteSqlCommand(string p,params object[] os)
{
this.Database.ExecuteSqlCommand(p, os);
}
public void ExecuteSqlCommand(string p)
{
this.Database.ExecuteSqlCommand(p);
}
bool ContextI.AutoDetectChangedEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
}
}
I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).
Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.
namespace Test.Mocks
{
public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
{
public MockDatabaseContext(ConfigurationWrapper config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = "test.db";
optionsBuilder.UseSqlite($"Filename={dbPath}");
}
}
}
namespace Test.Mocks
{
public class MockInventoryFacade : InventoryFacade
{
public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
{
}
}
}
There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.
EF team is also going this way with IDbSet if you look at this design meeting note
For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.
Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications.
It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.
With this, you can leave your DbContext and DbSet as is and do your unit tests easily.
The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.
UPDATE with EF7
I still maintain that IDbContext would be useless and the problem comes from the DbConnection.
EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.
You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7
I'm trying to force EF Code First to re-initialize the database. My first thoughts were to call:
dbContext.Database.Delete();
dbContext.Database.Create();
This creates a new database but the seeding strategy (set using Database.SetInitializer<>) is ignored. I'm doing the above in the Application_Start method. Any ideas?
I have also tried:
dbContext.Database.Initialize(true);
One option is to create your own DatabaseInitializer that inherits from DropCreateDatabaseAlways.
An example of this would be.
public class MyInitializer : DropCreateDatabaseAlways<EmployeeContext>
{
protected override void Seed(EmployeeContext context)
{
context.Employees.Add(new Employee() {FirstName = "Marcy"});
base.Seed(context);
}
}
public class EmployeeContext : DbContext
{
static EmployeeContext()
{
Database.SetInitializer(new MyInitializer()); // using my own initializer
}
public IDbSet<Employee> Employees { get; set; }
}
Here's what I did to overcome this:
Add a flag in your context initializer
public bool WasSeeded = false;
Create a public method in your initializer and put your seed code there. I made sure to use only AddOrUpdate or other upsert methods, i.e. check the data is not in the DB before:
context.Students.AddOrUpdate
At the end set the flag to true
After you initialize the context, check the flag and if it is false run the logic manually:
if (!initializer.WasSeeded)
{
initializer.SeedAndUpsert(context);
}
Database.SetInitializer(new CustomInitializer()); //CustomInitializer contains the overriding Seed method
using (var context = new CustomDatabaseContext())
{
context.Database.Initialize(force: true);
}