EF share class from two dbcontext - entity-framework

I want to try to share a class (es. user) from two dbcontext.
The idea is 1st dbcontext has all method to work with user (add/remove/update/etc) the 2nd dbcontext only need to access (read the user data).
To do that I have created a class abstract Users and I add this class to the db context, so the problem is when create the migration for the 1st dbcontext and the 2nd.
In my 1st I want to track the changes on my POCO user class in the second I don't want to track/create the table.
I try to use Ingore on OnModelCreating but in this way the code first not create the migration but dbcontext don't have the correct model creating and I'm not able to do operation to table db (i use this approch suggested on EF Data Pints
--Update--
[Table("User")]
public abstract class BaseUser {
[Key]
public virtual int Id {get;set;}
public virtual string Name {get;set;}
}
//DB context 1
public class OUser : BaseUser{
}
public class oneDbContext : DbContext
{
public virtual IDbSet<OUser> OneUsers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
....
}
//DB context 2
public class MUser : BaseUser{
}
public class twoDbContext : DbContext
{
public virtual IDbSet<MUser> TwoUsers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore<MUser>();
}
So now if I call the code first with Add-Migration whith modelBuider.Ingore the table User not appear in the script but when I try to access to table via db context I catch the error
The entity type Muser is not part of the model for the current context.
But if I uncomment the ingore the access to table work fine but model try to add the table User.

Related

EF Core Fluent API, set IsRequired on all entities to generate a non-null db column

I'm working on a Razor pages web app which works directly with a db context...yes this is not ideal but is what I'm stuck with for the time being.
In the data model, each object inherits from a base entity class containing audit data, e.g.:
public class BaseEntity
{
[Key]
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
...etc.
public class Table1 : BaseEntity
{
public string TestItemName { get; set; }
}
In the database, I want CreatedBy to be required (not null), but I don't want to use the [Required] attribute since this will trigger the UI to validate the CreatedBy column. I don't want to expose this column in the UI and instead have service code which updates all of the audit properties based on Add/Insert.
What I'm looking for is a way via Fluent API which will give me the column type in the db that I need, e.g. NVARCHAR(MAX) NOT NULL.
I can accomplish this in the OnModelCreating method in the dbcontext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Table1>()
.Property(o => o.CreatedBy)
.IsRequired();
However this would require me to create a similar entry for every table in the model.
Is there code I can use in OnModelCreating which could accomplish this for all entities? Something like this (this is just pseudo-code, but looking to give an idea):
var entityTypes = modelBuilder.Model.GetEntityTypes().Select(o => o.GetType()).ToList();
entityTypes.ForEach(e =>
{
e.Property("CreatedBy").IsRequired();
});
Implement your entity configurations in discrete classes that implement IEntityTypeConfiguration. Your implementations should inherit from a base implementation that configures BaseEntity and the Configure method should be virtual with overriding implementations calling the base class' method:
public abstract class BaseEntityConfiguration<TEntity>
: IEntityTypeConfiguration<TEntity>
where TEntity : BaseEntity
{
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.Property(be => be.CreatedBy)
.IsRequired();
// etc
}
}
public class SomeEntityConfiguration : BaseEntityConfiguration<SomeEntity>
{
public override void Configure(EntityTypeBuilder<SomeEntity> builder)
{
// call base class method to configure BaseEntity properties
base.Configure(builder);
// configure remaining SomeEntity-specific properties/etc
builder.TestItemName.IsRequired();
}
}
You'll need to inform the model builder to use your configuration classes. For example, if your config classes are in the same assembly as your DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(
typeof(YourDbContext).Assembly);
}

How to set the Status of an entity to modified for a context derivin from ApplicationDBContex?

I'm using an assembly (dll) that contain my Context class, this class holds both the identity tables and my own tables:
namespace SharedModels
{
public class ApplicationDbContext : Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext();
public DbSet<UserTask> Tasks { get; set; }
public static ApplicationDbContext Create();
protected override void OnModelCreating(DbModelBuilder modelBuilder);
}
}
I can't change the code in it, but I need to set an entity (from Tasks table) to modified, but I can't find the Entry method on that context:
apparently it doesn't inherit from DBContext class, is there a way to accomplish this?
It turns out that I should add a reference to: Microsoft.AspNet.Identity.EntityFramework;
I couldn't find this without distrusting the Intellisense:

The entity type <myType> is not part of the model for the current context

Using EF6, .NET 4.0
I have my own custom models and am using Database First approach. I've modified the edmx to use the same namespace as my custom models. I'm getting the error in the subject of the thread when running the code. The class 'User' does exist in my model and in my edmx. I also have my custom DbContext like so:
public class MyEntities : DbContext
{
public MyEntities()
: base("Name=MyEntities")
{
User = Set<User>();
}
public virtual DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
Any ideas?

EntityFramework how to not map a class but do map it's inherited properties

We use EntityFramework 6.1 with CodeFirst in our web mvc application (StdWebApp). Now we want to make a new custom version of this application (CustomWebApp) .
The CustomWebApp will use most of the code of the standard one, in it's domain model it will extend the Person class.
In CustomDomain we make implement a new DbContext that must connect with the database of the custom app (CustomSqlDb).
In (C#) code there is no problem that there is a Person in Domain and in CustomDomain. However we have not been able to devise a mapping for Person in the Custom DbContext that will:
Create a single "Person" table.
Contains fields form "CustomDomain.Person" AND those from "Domain.Person".
We tried some variants like this:
modelBuilder.Entity<Person>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Person");
}
);
using this document as our inspiration msdn mapping types
But EF complains about the simple name beeing equal.
Obviously we could rename the "Person" in "CustomDomain" to "PersonCustom" but that could lead to a lot of silly names if we have to do this again in the future like "PersonCustomExtraSpecial" etc.
Thoughts anyone?
UPDATE
we tried the solution suggested by mr100, here is the complete code:
namespace Domain
{
public class Person
{
public int Id { get; set; }
public string Stuff { get; set; }
}
}
namespace CustomDomain
{
public class Person : Domain.Person
{
public string ExtraStuff { get; set; }
}
}
namespace CustomDomain
{
public class DbModel : DbContext
{
DbSet<CustomDomain.Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CustomDomain.Person>().Map(m => m.ToTable("Person"));
}
}
}
This still result in the error
The type 'CustomDomain.Person' and the type 'Domain.Person' both have the same simple name of 'Person' and so cannot be used in the same model. All types in a given model must have unique simple names. Use 'NotMappedAttribute' or call Ignore in the Code First fluent API to explicitly exclude a property or type from the model.
So we added the following code:
namespace CustomDomain
{
public class DbModel : DbContext
{
DbSet<CustomDomain.Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<Domain.Person>();
modelBuilder.Entity<CustomDomain.Person>().Map(m => m.ToTable("Person"));
}
}
}
Still same result.
To achieve this your DbContext class in CustomWebApps should have property People defined like this:
public DbSet<CustomDomain.Person> People {get; set;}
and no property:
public DbSet<Domain.Person> People {get; set;}
even if it comes from StdWebApp DbContext class from which CustomWebApp DbContext class may derive (if that is the case for you). Additionally you may set properly table name:
modelBuilder.Entity<Person>().ToTable("Person");

Schema not supported error in asp.net mvc web api

I am working on asp.net mvc 4 web api. I am using code first with existing database model. I have a single table in my database so i have the entity class like,
public class Tab1
{
[Key]
public int Field1{get; set;}
public string Field2{get; set;}
}
I have DBContext file like,
public class MyDBContext:DbContext
{
public DbSet<Tab1> Table{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Bar>().ToTable("bars");
}
}
and my Get Action is like
public List<Bar> GetTables()
{
MyDBContext context=new MyDBContext();
return context.Table.ToList();
}
But I am getting an error Schema specified is not valid error 0064: Facet 'MaxLength' must not be specified for type 'mediumtext'.. so please guide if i did any mistake in the process.
Here i have one more class like
public class Tab2:Tab1
{
public string Filed3{get; set;}
}
I dont want to create table in database with tab2 since i used tab2 class for returning custom records. I got the above error due to Tab2 inheriting from tab1 when i remove class tab2 it works as usual. so please guide me.
If you problem is only caused when introducing the "Tab2" class in the model and you don't really want "Tab2" to be stored in the database why don't you just annotate the "Tab2" class with the the [NotMapped] attribute or use the fluent configuration ModelBuilder.Ignore.