Mixing Model first and Code first - c#

We created a web application using the model first approach. A new developer came into the project and created a new custom model using the code first approach (using a database file). The
Here is the code first database context.
namespace WVITDB.DAL
{
public class DashboardContext : DbContext
{
public DbSet<CTOReview> CTOReviews { get; set; }
public DbSet<Concept> Concepts { get; set; }
//public DashboardContext()
// : base("name=DashboardContext")
//{
//}
// protected override void OnModelCreating(DbModelBuilder modelBuilder)
// {
// //modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
// }
}
}
The following controller method throws an error Could not find the conceptual model type for 'WVITDB.Models.FavoriteProject'. and refers to the original database model. We are not sure why (or how) it is calling that.
public ViewResult Index()
{
var d = db.Concepts.ToList(); //Throws error here
return View("Index",d);
}
When the DashboardContextclass is instantiated the error are shows up for both of the DBset properties.
Is there are a reason why the controller calling the wrong database?
EDIT:
FavoriteProject is in a different context (our main data model) and not related to the new custom model.

Found an answer, it maybe not what you want to hear though:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/d2a07542-cb33-48ba-86ed-4fdc70fb3f1a
"If you are using the default code generation for the EDMX file then the generated classes contain a series of attributes to help EF find which class to use for each entity type. EF currently has a restriction that POCO classes can't be loaded from an assembly that contains classes with the EF attributes. (Short answer is no, your classes need to be in separate projects).
This is a somewhat artificial restriction and something that we realize is painful and will try and remove in the future."
So the workaround would be to split the classes into two different assemblies.

ajpaz - you may have to 'map' your existing model to the database table programatically. i'm assuming from the error message that its looking for the FavouriteProject table/class mapping. maybe the db has this defined as a singular, in which case try:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<FavouriteProjects>().ToTable("FavouriteProject");
}
you'd also need to do a dbset as per above (or some permutation of plurals):
public DbSet<FavouriteProjects> FavouriteProjects{ get; set; }
might be miles off, just a thought
[edit] - overiding your code 1st dbcontext in web.config (under connectionstrings [name MUST match your dbcontext name]):
<add name="DashboardContext" connectionString="Data Source=remote.sqlserver.server;Initial Catalog=code_first_db;Persist Security Info=True;MultipleActiveResultSets=True;User ID=code_first_db_user;Password=password" providerName="System.Data.SqlClient"/>

Related

Entity Framework Core DbContextOptionsBuilder.UseModel creates EntityTypes that have no properties

I am working on a .NET Core project using entity framework core (2.0.1).
I have a plugin architecture requiring different models to be loaded based on the plugins attached, so trying to dynamically load the models when adding the dbcontext to the DI container using the DbContextOptionsBuilder.UseModel method.
Regardless on if I define a new Model or a ModelBuilder, the EntityTypes I am adding do not appear to be doing so correctly and once added to the dbcontext do not appear to have any properties.
I am not sure if there is a convention I need to be adding for this to work, or what I may be missing. Any help would be appreciated.
_services.AddDbContext<DataContext>(options =>
{
switch (_config.DatabaseType.ToLower())
{
case "postgres":
options.UseNpgsql(_config.ConnectionString);
break;
case "sqlserver":
options.UseSqlServer(_config.ConnectionString);
break;
}
var convention = new Microsoft.EntityFrameworkCore.Metadata.Conventions.ConventionSet();
var mb = new ModelBuilder(convention);
foreach (var definition in definitionList)
{
mb.Entity(definition.Type);
}
options.UseModel(mb.Model);
});
Resolves into:
Correctly creates the 5 EntityTypes, but then once I expand one of the Entity Types it has no properties.
If I do the same using the standard convention of adding the EntityType via the override of the dbcontext onmodelbuilding, the properties are all there correctly...
Yes, there are a few conventions by default, one of which is a PropertyDiscoveryConvention which sounds like it would make sure that all properties are added by default, but also other likely important ones like a KeyDiscoveryConvention, and lots of conventions that take care of identifying the mapping attributes.
You could probably ensure that you create the right conventions but it may be easier to move your logic into the database context instead. That way you can build on top of all the standard conventions, like one would normally do, and you won’t need to take care of that yourself. So maybe something like this:
class MyContext : DbContext
{
private readonly IDbContextConfigurator _dbContextConfigurator;
public MyContext(DbOptions<MyContext> dbOptions, IDbContextConfigurator dbContextConfigurator)
: base(dbOptions)
{
_dbContextConfigurator = dbContextConfigurator;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
_dbContextConfigurator.Configure(modelBuilder);
}
}
So inside that IDbContextConfigurator you could then retrieve your configuration and configure your model directly on the model builder.

allowing a user to define a table at runtime using entity framework

is it possible to dynamically build entities in entity framework 6 using code first?
is it also possible to add properties to those entities at runtime?
Can those entities reference each other using foreign keys?
If someone could point me in the right direction if this is possible, i would really appreicate it.
EDIT
i have changed the title to reflect more of what i would like, so u can see why i asked the questions i asked.
Basically i would like to create a system where a user can define the objects(tables) they want, with the properties on that object (columns in table) as well as the references to each object (relationships between tables).
Now each object would have an Id property/column. i was thinking of atoring these definitions in an eav like table structure but i have other ibjects that are defined at design time and i like to use linq queries on these objects. I would also like to be able to build linq queries on these objects as users will want to report on this data. Building the linq queries should be fine as could use dynamic linq for this (Maybe)?
Currently to create such a system i have created a table that has many text fields, many number fields, many relationship fields and users can use which ones they want. But this is just 1 table and i think this is going to bite me in the bottom in the end, thus why i would like to take it to the next level and build separate tables for each object.
if anyone knows of a better way or maybe experienced something similar, glad to hear opinions.
Ive been interested in this topic since ef4.
Have a real world solution that could use it.
I dont...
Rowan Miller is one of the EF developers. He wrote a blog on this topic.
Dynamic Model creation Blog Explaining how you might do it.
A github example buybackoff/Ractor.CLR see OnCreating Showing how.
It would appear ok, but has a many practical restrictions that make
a recompile with generated code or hand code more practical.
It is also why i have not down voted others. :-)
Would it be fun watching someone dig their own grave with a teaspoon?
Consider the runtime implications.
These approach still rely on the POCO type discovery.
the an assembly can be generated from code on the fly.
And then there is SO POCO and runtime
During context creation the initializer runs. You adjust the model.
The auto migrate then adds the news properties and tables.
So during that period of time NO other contexts can be instantiated.
Only non EF access possible during the automatic migration.
So you still have a logical outage.
You are now using previously unknown pocos, in unknown tables.
What repository pattern are you using...
eg I used this type of pattern....
private IRepositoryBase<TPoco> InstantiateRepository(BaseDbContext context, Type repType, params Type[] args) {
Type repGenericType = repType.MakeGenericType(args);
object repInstance = Activator.CreateInstance(repGenericType, context);
return (IRepositoryBase<TPoco>)repInstance;
}
and cast this against IRepository after making a dynamic call to the factory.
But i was unable to avoid dynamic calls. Sticky situation.
good luck....
Edit / After thought
I read a blog about ef 7
There are some very interesting comments from Rowan about potentially not needing CLR types. That makes the dynamic game a bunch easier.
You could try the ef7 beta if brave.
You can create an EF model dynamically using reflection:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
foreach (Type type in ...)
{
entityMethod.MakeGenericMethod(type)
.Invoke(modelBuilder, new object[] { });
}
base.OnModelCreating(modelBuilder);
}
it possible to dynamically build entities
The short answer is no, one cannot dynamically build new or existing entities once EF has defined them during design time.
is it also possible to add properties to those entities at runtime
But that does not mean one has to live with those entities as they are... To achieve a dynamism one can extend the entities via Partial class to the entity. Then one can have any number of new properties/methods which could achieve what the runtime aspect which possibly you are looking for past a generated entity.
Can those entities reference each other using foreign keys?
Not really, but it is not clear what you mean.
If the entity was generated in design time and during runtime a new FK constraint was added to the database, then an entity could be saved if it does not know about the FK, but if the FK requires a value then the process of saving would fail. Extraction from the database would not fail.
Q: is it possible to dynamically build entities in
entity framework 6 using code first?
A: No
Q: is it also possible to add properties to those entities at runtime?
A:No
Q: Can those entities reference each other using foreign keys?
A: Unless you've defined the entity beforehand, no.
Maybe you've confused things with what's called CodeFirst, where you write your domain / business models in C#, define their relationships with other entities, and then generate a database based on your C# models...
Here's an overly simplistic example that you can get started with if that's what you're trying to achieve.
First make sure you have EntitiyFramework installed... you can get it from NuGet...
pm> Install-Package EntityFramework
Then copy the code below to your project
public class User
{
public User()
{
this.Id = Guid.NewGuid().ToString();
}
public string Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts {get;set;}
}
public class Post
{
public Post()
{
this.Id = Guid.NewGuid().ToString();
}
public string Id { get; set; }
public string UserId { get; set; }
public virtual User Author {get;set;}
public string Title { get; set; }
public string Body { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
this.ToTable("Users");
this.HasKey(user => user.Id);
this.Property(user => user.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(user => user.Name).IsRequired();
this.HasMany(user => user.Posts).WithRequired(post => post.Author).HasForeignKey(post => post.UserId);
}
}
public class PostConfiguration : EntityTypeConfiguration<Post>
{
public PostConfiguration()
{
this.ToTable("Posts");
this.HasKey(post => post.Id);
this.Property(post => post.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(post => post.UserId).IsRequired();
this.Property(post => post.Title).IsRequired();
this.Property(post => post.Body).IsRequired();
this.HasRequired(post => post.Author).WithMany(user => user.Posts).HasForeignKey(post => post.UserId);
}
}
public class ExampleContext : DbContext
{
public ExampleContext() : base("DefaultConnection")
// Ensure you have a connection string in App.config / Web.Config
// named DefaultConnection with a connection string
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new PostConfiguration());
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
Once you've done that... Open the package manager console and type in the following commands...
pm> Enable-Migrations
pm> Add-Migration InitialMigration
pm> Update-Database
And you should then have your database generated for you from that

Entity Framework: why still trying to read from a removed entity in the DbContext?

I have a DbContext with many classes/entities targeting a Firebird database. I used to have an entity named DinnerPasses, which was declared (as all others) using Code First:
public class FreezedOrdersContext : DbContext
{
public FreezedOrdersContext()
: base("name=ConnectionString")
{
}
// The deleted entity... (NOTE: THIS IS NO LONGER IN THE FILE...)
public virtual DbSet<DinnerPass> DinnerPasses { get; set; }
public virtual DbSet<FirebirdFreezedSalesOrder> FreezedSalesOrders { get; set; }
// Other entities, removed for clarity...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Database.SetInitializer<FreezedOrdersContext>(null);
// Some of the lines still in the file...
modelBuilder.Entity<FirebirdFreezedSalesOrder>().HasKey(p => new { p.ORDERTYPE, p.CUSTOMERTYPE, p.TABLEID, p.SUBORDERNUMBER });
modelBuilder.Entity<FirebirdFreezedSalesOrder>().ToTable("FREEZEDSALESORDER");
// NOTE: This 2 lines are NO LONGER in the file...
modelBuilder.Entity<DinnerPass>().HasKey(p => p.NUMBER);
modelBuilder.Entity<DinnerPass>().ToTable("GENERALINFO");
}
}
The DinnerPasses entity was deleted. Now, reading any of the other entities goes fine, but when I try to save some other entities into the database db.SaveChanges();, I get the following exception:
"Dynamic SQL Error SQL error code = -204 Table unknown DinnerPasses At line 6, column 8"
System.Exception {FirebirdSql.Data.FirebirdClient.FbException}
So, I guess that EF created some model file somewhere that allows it "remember" that entity (and since the line modelBuilder.Entity<DinnerPass>().ToTable("GENERALINFO"); is no longer part of the file, it is trying to get the DinnerPass entity from a table of the same name).
How can I fix this? Where are the model files for this? They are certainly not found anywhere in my project folder...
Thanks in advance.
You need to remove the DbSet and the entity class from your context entirely (including references from other entities!). If you don't specify any additional metadata, then Entity Framework will assume a tablename derived from the entity classname.
Ok, so I found out what happened:
I removed the DinnerPasses entity and replaced it with a new entity called GeneralInfo that was more appropriate (it gets more info from the table, instead of my initial needs that was the Dinner Pass information within that table).
Here is the issue: When I created the new GeneralInfo class, I copied a property from the old DinnerPass class (called FormattedDinnerPasses) into the new GeneralInfo class/entity. When I changed that property to a method, it no longer tried to access the "DinnerPasses" table.
So, I think the problem was having a property that didn't have a backing variable (the property just did a bunch of calculations and returned a list of formatted items). Maybe you can have one but need to give it an attribute indicating that it must be ignored when Entity Framework is binding to the table...

How to preserve the Model.Context.cs file header content after updating model from db with Entity Framework?

The Model.Context.cs file is automatically generated when using Entity Framework Database First.
I have modified the header part of the class to be compatible with a Unit of Work and Repository pattern:
public partial class MyDatabaseContext : DbContext, IDbContext
{
public MyDatabaseContext()
: base("name=MyDatabaseContextEntities")
{
// disable lazy loading for best practices - keeps from accidentaly loading large entity graphs
Configuration.LazyLoadingEnabled = false;
}
// refactored
public new IDbSet<T> Set<T>() where T : class
{
return base.Set<T>();
}
public override int SaveChanges()
{
// this.ApplyStateChanges();
return base.SaveChanges();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
.
.
.
The issue is that whenever I update the model from the db, obviously, this file gets overwritten.
I've saved the relevant code in a commented out portion of the *.config, and simply copy/paste it back in place whenever the model is updated.
Even though the model is not updated that frequently, I'd like to know if there is a way of preserving this content so I don't have to go through the extra step of copy/pasting.
For the added members, you can create another file that contains another partial of the class. This new file won't be overwritten so anything you've added there should persist between updates.
For the changes that aren't new members (like the added line in the constructor), you can edit the Model.Context.tt file directly. This is a simple T4 Text Template used to re-generate the code when the model is updated. It is similar to an ASP.NET page; however, instead of using C# to generate HTML, it uses C# to generate more C#.

Entity Framework + Autofac: How to properly reload mappings / configurations?

BACKGROUND:
Our core framework loads all entity framework mappings from itself, the main application and any modules we have installed by using an interface (below):
public interface IEntityTypeConfiguration : IDependency
{
}
and we have a DbContext in our core framework like this, which loads all the mappings:
public class DefaultDbContext : DbContextBase
{
private readonly Lazy<IEnumerable<IEntityTypeConfiguration>> configurations;
public DefaultDbContext(Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base()
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
public DefaultDbContext(string connectionString, Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base(connectionString)
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (dynamic typeConfiguration in configurations.Value)
{
modelBuilder.Configurations.Add(typeConfiguration);
}
Database.SetInitializer(new CreateTablesIfNotExist<DefaultDbContext>());
}
}
So this way we have a single DbContext for everything.
PROBLEM:
We've run into an issue whereby when we dynamically add new modules (which have their own mappings), then EF does not load those mappings ever, even when we are sure that a new instance of DefaultDbContext has been created. So, it must be that EF is cacheing the mappings somewhere. Is there some way to clear the cache?
FINAL NOTE:
As you may have guessed, we are using an IoC, namely Autofac. If you need any further info, just ask.
Any ideas, anyone?
The model is cached for performance reasons.
The following excerpt explains what is going on
Model Caching
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain.
This text also mentions a property called CacheForContextType but this didn't make it into the final release of EF5.
This second link provides a glimmer of hope but again is dated before the final release of EF5
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
Personally I think you're going to have to find a way of knowing all of your models up front ...
Solved! We found this constructor on the DbContext class:
public DbContext(string nameOrConnectionString, DbCompiledModel model);
I can't share all of the code here, but basically we're creating a new DbCompiledModel and passing that in whenever necessary.

Categories