Multiple DbContext in ASP MVC: Possible to avoid IdentityDbContext inheritance? - asp.net-mvc

I'm using EntityFramework 6. I would like to split my DbContext into multiple smaller ones. Edit: I have a single database I wish to connect to.
I will have a single DbContext with all the entities and migrations that only one central application will use. Other applications will use the smaller DbContext without migrations.
I have found that I need to inherit all DbContext from IdentityDbContext, even if they use none of it.
internal class SmallerDbContext : IdentityDbContext<ApplicationUser,
ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public DbContext<Entity1> NotInSmallerDbContext { get; set; }
public DbContext<Entity1> InSmallerDbContext { get; set; }
}
I would like this to be:
internal class SmallerDbContext : System.Data.Entity.DbContext
{
public DbContext<Entity1> InSmallerDbContext { get; set; }
}
But this yields the following errors:
Paris.DAL.Repo.DbContext.ApplicationUserLogin: : EntityType 'ApplicationUserLogin' has no key defined. Define the key for this EntityType.
Paris.DAL.Repo.DbContext.ApplicationUserRole: : EntityType 'ApplicationUserRole' has no key defined. Define the key for this EntityType.
ApplicationUserLogins: EntityType: EntitySet 'ApplicationUserLogins' is based on type 'ApplicationUserLogin' that has no keys defined.
ApplicationUserRoles: EntityType: EntitySet 'ApplicationUserRoles' is based on type 'ApplicationUserRole' that has no keys defined.
I have tried to add these tables to the DbContext, but to no avail.
public IDbSet<ApplicationUser> Users { get; set; }
public IDbSet<ApplicationRole> Roles { get; set; }
Is there any way I can create DbContext that does not inherit from IdentityDbContext?

I was on the right path by adding the objects to the DbContext.
You need to add only two, the User and UserLogin. The others are not needed.
public DbSet<ApplicationUser> Users { get; set; }
public DbSet<ApplicationUserLogin> UserLogins { get; set; }
Additionally, you need to set the correct table for both objects and you need to add some of virtual properties so that Entity Framework can handle these types as it would any of your other classes.
[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
}
[Table("AspNetUserLogins")]
public class ApplicationUserLogin : IdentityUserLogin<int>
{
[Key, Column(Order = 0)]
public override string LoginProvider { get; set; }
[Key, Column(Order = 1)]
public override string ProviderKey { get; set; }
[Key, Column(Order = 2)]
public override int UserId { get; set; }
}
Now, your DbContext no longer has to inherit from IdentityDbContext.

Related

Make foreign key to ApplicationUser in auxiliary table (EntityFramework Identity)

I have my ApplicationUser model defined like so:
public class ApplicationUser : IdentityUser
{
public virtual UserProfileInfo UserProfileInfo { get; set; }
}
With UserProfileInfo being an auxiliary table containing extra user data, defined as such:
public class UserProfileInfo
{
public int Id { get; set; }
public string SuperiorId { get; set; }
[ForeignKey("SuperiorId")]
public virtual ICollection<ApplicationUser> Superior { get; set; }
}
Each user has one or more people who are superior to them, in a business hierarchy. However, attempting to do a migration results in the following error:
The ForeignKeyAttribute on property 'Superior' on type 'Project.Models.UserProfileInfo' is not valid. The foreign key name 'SuperiorId' was not found on the dependent type 'Project.Models.ApplicationUser'.
How can I make a foreign key reference to ApplicationUser in my situation?
You need to do it the other way around, the ID is the foreignkey of the navigational property:
public class UserProfileInfo
{
public int Id { get; set; }
[ForeignKey("Superior")]
public string SuperiorId { get; set; }
public virtual ICollection<ApplicationUser> Superior { get; set; }
}

One to many with applicationuser

If this is a dupp, by all means direct me to the answer.
ASP.NET, MVC5, EF6
Each application user can have many TfsAccountCredentials
IdentityModel.cs has the following:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
TfsAccountCredentials.cs has the following:
public class TfsAccountCredentials
{
public int Id { get; set; }
//other properties
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
TfsAccountCredentialsDb has the following:
public class TfsAccountCredentialsDb : DbContext
{
public TfsAccountCredentialsDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TfsAccountCredentials>()
.HasRequired(ac => ac.ApplicationUser)
.WithMany(ac => ac.TfsAccountCredentials)
.HasForeignKey(ac => ac.ApplicationUserId);
}
}
IdentityDb.cs has the following:
public class IdentityDb : IdentityDbContext<ApplicationUser>
{
public IdentityDb() : base("DefaultConnection")
{
}
}
Two things. First, when I add a migration using the Identity context, part of the script it generates adds the TfsAccountCredentials table, which already exists due to an earlier migration for the TfsAccountCredentials context.
Second, when I add a migration using the TfsAccountCredentials context, I get the following error:
TfsTeamStatus.Web.DataContexts.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
TfsTeamStatus.Web.DataContexts.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
EDIT
My final solution:
IdentityModel.cs contains the following:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
TfsAccountCredentials.cs contains the following:
public class TfsAccountCredentials
{
public int Id { get; set; }
//other properties
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
ApplicationDb.cs contains the following:
public class ApplicationDb : IdentityDbContext<ApplicationUser>
{
public ApplicationDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
So TfsAccountCredentialsDb.cs and IdentityDb.cs got combined.
Why you are making to separate DB? I think you want make 2 table in same DB not different DB so remove your TfsAccountCredentialsDb and add your TfsAccountCredentials to IdentityDb:
public class IdentityDb : IdentityDbContext<ApplicationUser>
{
public IdentityDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
You don't need IdentityDb because IdentityDbContext<ApplicationUser> is the context that handles Identity issues. So then you can either:
A) Have TfsAccountCredentialsDb inherit from IdentityDbContext<ApplicationUser>. This will allow you to reference ApplicationUser in your models. The DbSet for ApplicationUser is in the base class you can't see.
B) If you want TfsAccountCredentialsDb to inherit from DbContext, then you will have to add a copy of ApplicationUser in that context along with it's DbSet that you can use to reference within your app's context.

EntityType 'SelectListItem' has no key defined. Define the key for this EntityType

i Have a Model Class
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public ICollection<SelectListItem> CourseList { get; set; }
}
and the
public class StudentContext : DbContext
{
public DbSet<Student> Students { get; set; }
}
and i try ti use it as
List<Student> sList = db.Students.ToList();
and i am getting following error
\tSystem.Data.Entity.Edm.EdmEntityType: : EntityType 'SelectListItem' has no key defined. Define the key for this EntityType.
\tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'SelectListItems' is based on type 'SelectListItem' that has no keys defined.
Please suggest where i am doing wrong.
Add [NotMapped] annotation to the LIST class
[NotMapped]
public List<SelectListItem> ListItems { get; set; }
NotMapped Code first convention dictates that every property that is of a supported data type is represented in the database. But this isn’t always the case in your applications. For example you might have a property in the Blog class that creates a code based on the Title and BloggerName fields. That property can be created dynamically and does not need to be stored. You can mark any properties that do not map to the database with the NotMapped annotation such as this BlogCode property.
[NotMapped]
public string BlogCode
{
get
{
return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
}
}
You can refer to the link here on EF code first Data Annotations
You should not be attempting to store SelectListItem in the database, as this is MVC specific concept. Instead create a custom entity class and use it instead;
public class Course
{
public int CourseId { get; set; }
public string CourseTitle { get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public ICollection<Course> CourseList { get; set; }
}
public class StudentContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
}

EF6 I have GUID for UserId Stored in a table but want to add ApplicationUser to the Model

My Application is all fine and within IdentityModels I set each class (table). But I want to show in my Razor View the UserName from AspNetUsers and not the GUID. I currently store the GUID but thats all i'm able to display in the views
I'm thinking there must be a built in easy way to do this - and that I don't need to do any mapping or do i
I'm using EF6 and MVC4.5
Here is my class :
public partial class x23BatchImport
{
public int x23BatchImportId { get; set; }
public Nullable<DateTime> DateTimeFromFilename { get; set; }
public string UserId { get; set; }
public string Filename { get; set; }
public decimal? Length { get; set; }
public Nullable<DateTime> StartDateTime { get; set; }
public Nullable<DateTime> StopDateTime { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
}
...here is an extract from IdentityModels.cs
namespace AscendancyCF.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
//public System.Data.Entity.DbSet<AscendancyCF.Models.ApplicationUser> ApplicationUser { get; set; }
public System.Data.Entity.DbSet<AscendancyCF.Models.SupplyPointType> SupplyPointTypes { get; set; } ETC ETC
.....NB all my tables are declared here then I use OnModelCreating to set up relationships some of the time...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Reference : http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx
base.OnModelCreating(modelBuilder);
// Configure the 1-1
modelBuilder.Entity<SupplyPoint>()
.HasOptional(a => a.SupplyPointAddress)
.WithMany()
.HasForeignKey(u => u.SupplyPointAddressId);
}
Entity Framework has a set of model and property naming conventions that it uses by default. Currently, it's not able to figure out that UserId is a foreign key to an ApplicationUser.
If you don't want to add any manual mappings, you have to change your naming. The simplest would be to rename the ApplicationUser property to User.
public virtual ApplicationUser User { get; set; }
When doing your queries, use Include() to eager load the User property with the matching ApplicationUser...
// using System.Data.Entity; // add this using to use Include()
var context = new ApplicationDbContext();
var batchImport = context.x23BatchImport
.Include(x => x.User)
.(x => x.x23BatchImportId == 1)
.Single();
var username = batchImport.User.UserName;
Your other alternatives are:
Change UserID property to ApplicationUserId
Specify the foreign key in a manual mapping in OnModelCreating()
Specify the foreign key on the model using data annotations

MVC No Key Defined

I am getting this error in my MVC Application:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'CustomerModel' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �Customer� is based on type �CustomerModel� that has no keys defined.
My Customer Model looks like this:
public class CustomerModel
{
public string Name { get; set; }
public int CustomerID { get; set; }
public string Address { get; set; }
}
public class CustomerContext : DbContext
{
public DbSet<CustomerModel> Customer { get; set; }
}
By default, Entity Framework assumes a key property called Id exists in your model class. Your key property is called CustomerID, so Entity Framework can't find it.
Either change the name of your key property from CustomerID to Id, or decorate the CustomerID property with the Key attribute:
public class CustomerModel
{
public string Name { get; set; }
[Key]
public int CustomerID { get; set; }
public string Address { get; set; }
}
public class CustomerContext : DbContext
{
public DbSet<CustomerModel> Customer { get; set; }
}

Resources