Can we mix new table and existing view in EF code first - entity-framework

I created some classes and a table in db for those classes with migration. I tested my code by adding some data to the classes,saved by EF and saw the data saved properly in db.
Later when I created a view in db and maped that view in code the problems started. When I tried to query this way:
using (var db = new TestDBContext())
{
var listMyViews = db.vwCustomer.ToList();
}
I was getting an error message like
Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
So EF is telling me to migrate features to create view in db but view exists already. So why do I need to recreate it by migration?
my full code with view mapping and class
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
public class vwCustomer
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
}
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new vwCustomerConfiguration());
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
public DbSet<vwCustomer> vwCustomer { get; set; }
}
public class vwCustomerConfiguration : EntityTypeConfiguration<vwCustomer>
{
public vwCustomerConfiguration()
{
this.HasKey(t => t.CustomerID);
this.ToTable("vwCustomer");
}
}
Later I tried to see if any migration is pending issuing Add-Migration "My_vwCustomer". I saw new migration code being added as below. It seems there is no migration pending.
public partial class My_vwCustomer : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.vwCustomers",
c => new
{
CustomerID = c.Int(nullable: false, identity: true),
FirstName = c.String(),
})
.PrimaryKey(t => t.CustomerID);
}
public override void Down()
{
DropTable("dbo.vwCustomers");
}
}

Another way we can do it and it solve my problem. see the code.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<YourDbContext>(null);
base.OnModelCreating(modelBuilder);
}
code taken from here https://stackoverflow.com/a/6143116/6188148
we can follow this approach too.
public partial class AddingvwCustomer : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
i guess this will works too but not tested myself.
we can use the Fluent API to configure it using the Ignore method:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<MyClass>();
}
thanks

Related

How do I fix this SQLite error: SQLite Error 1: 'table "StudentCourses" already exists'

I'm creating a CRUD project in asp.net entity framework, and from my understanding, in order to see the data on the HTML page I have to scaffold the pages. For example I have two entity models Student and Major
This is the Student entity
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Major")]
public int? MajorId { get; set; }
public Major Major { get; set; }
[ForeignKey("Advisor")]
public int AdvisorId { get; set; }
public Advisor Advisor { get; set; }
public ICollection<StudentCourses>? StudentCourses { get; set; }
}
This is the Major entity
public class Major
{
public int MajorId { get; set; }
public string MajorName { get; set; }
public ICollection<Student> Students { get; set; }
public ICollection<Advisor> Advisors { get; set; }
public ICollection<MajorCourse> MajorCourses { get; set; }
}
If I want to see the Student data I have to create a Students folder and add a new Scaffolding along with a DbContext like your_namespace.Data.StudentContext. I would also have to follow the same steps for the Major entity but am I correct to use another DbContext? For example: your_namespace.Data.MajorContext. This is what I have done but when I try to make migrations and update the database in the your_namespace.Data.MajorContext, I get an error that reads SQLite Error 1: 'table "StudentCourses" already exists'.`
How do I fix this error?
I should also add the Context classes:
This is the StudentContext class:
public class AdvismentContext : DbContext
{
public AdvismentContext(DbContextOptions<AdvismentContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Major> Majors { get; set; }
public DbSet<Advisor> Advisors { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<MajorCourse> MajorCourses { get; set; }
public DbSet <StudentCourses> StudentCourses{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.ToTable("Students");
modelBuilder.Entity<Major>()
.ToTable("Majors");
modelBuilder.Entity<Advisor>()
.ToTable("Advisors");
modelBuilder.Entity<Course>()
.ToTable("Courses");
//modelBuilder.Entity<MajorCourse>()
// .ToTable("MajorCourse");
//.HasKey(mc => new { mc.MajorId, mc.CourseId });
}
And this is the MajorContext class:
public class MajorContext : DbContext
{
public MajorContext (DbContextOptions<MajorContext> options)
: base(options)
{
}
public DbSet<Advisment.Models.Major> Major { get; set; } = default!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Major>()
.ToTable("Major");
//modelBuilder.Entity<MajorCourse>() This is commented out because I was getting the same error that the table already exists.
// .ToTable("MajorCourse");
}
}
What am I doing wrong?

EF.core One to many referencing the same table

EF.core beginner here.
In my app I have Persons. These are connected to other persons (in that same table), and those connections have a 'level'. I've added a join table called connection to store who is connected to who and on what level. When trying to do an Add-migration i get the following error:
Unable to determine the relationship represented by navigation property 'Connection.Person' of type 'Person'. Either manually configure the relationship, or ignore this property from the model.
There is no problem on my other join tables that reference two different tables. What am i missing here?
I'm using EF.core 1.1, with .net 4.5, code below
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string NickName { get; set; }
public List<Connection> Connections { get; set; }
}
public class Connection
{
public int PersonId { get; set; }
public Person Person { get; set; }
public int SecondPersonId { get; set; }
public Person SecondPerson { get; set; }
public int ConnectionLevelId { get; set; } // connection Level
public ConnectionLevel Level { get; set; }
}
public class ConnectionLevel
{
public int Id { get; set; }
public string Name { get; set; }
//rights
}
public class testContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Connection> Connections { get; set; }
public DbSet<ConnectionLevel> ConnectionLevels { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=localhost\\SQLEXPRESS;Database=master;Trusted_Connection=True;");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Connection>().HasKey(s => new { s.PersonId, s.SecondPersonId });
base.OnModelCreating(modelBuilder);
}
}

EF code first telling me to do the migration for db object which is already is in db

i am working with EF code first. so initially i have no tables in database. so i wrote some class and when query those class then i saw EF code first create those tables in db but when i create sql server view in db and later map that view with my code in c# & EF project and when i try to query that view then i was getting error message as follows.
Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
i understand that EF is telling me to do the migration but if i migrate then EF will create that view in db again when the view is in db already exist.
so tell me how could i inform EF that my view is already is in db so migration is not required.
please guide me. thanks
EDIT 1
first time my database has no table. so i wrote some classes like below one.
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
}
when i query the customer like below query then EF create all required tables in db behind the curtains.
var bsCustomer = (from cu in db.Customer
where (cu.CustomerID == 2)
select new
{
cu,
Addresses = from ad in cu.Addresses
where (ad.IsDefault == true)
from ct in ad.Contacts
select ad,
}).ToList();
later i create a view in db and refer that view in code like below one.
public partial class vwCustomer
{
[Key]
public int CustomerID { get; set; }
public string FirstName { get; set; }
}
public class vwCustomerConfiguration : EntityTypeConfiguration<vwCustomer>
{
public vwCustomerConfiguration()
{
this.HasKey(t => t.CustomerID);
this.ToTable("vwCustomers");
}
}
so now my DbContext look like below one with view class reference
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new vwCustomerConfiguration());
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
public virtual DbSet<vwCustomer> vwCustomers { get; set; }
}
Error occur the moment i try to query the view
using (var db = new TestDBContext())
{
var listMyViews = db.vwCustomers.ToList();
}
the error was Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
thanks
Another way we can do it and it solve my problem. see the code.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<YourDbContext>(null);
base.OnModelCreating(modelBuilder);
}
code taken from here https://stackoverflow.com/a/6143116/6188148
we can follow this approach too.
public partial class AddingvwCustomer : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
i guess this will works too but not tested myself.
we can use the Fluent API to configure it using the Ignore method:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<MyClass>();
}
Add new migration as normally and from the migration code in Up (and Down) method remove code that tries to create new table manually (call to CreateTable method in Up and DropTable in Down). Then apply migration to your db and everything works perfectly.
Unfortunately automatic migration generation is not very intelligent tool and very often one need to manually specify how the database should be altered. In the documentation for EF migrations it is stated that it is perfectly fine to edit manually migrations code.

Entity Framework Code First Membership Provider Relationship Issue

I'm trying to code first on asp.net membership provider. When code first creates the table, it generates all tables and appropriate relationship to the bridge table but it also create an additional relationship from the AspNet_User(one) to Aspnet_Role(many). Do you know why it doing this? There shouldn't be any relationship between user and role table.
public class Aspnet_Role
{
public Aspnet_Role()
{
Aspnet_Users = new HashSet<Aspnet_Users>();
}
[Key]
public Guid RoleId { get; set; }
public string RoleName { get; set; }
public string LoweredRoleName { get; set; }
public string Description { get; set; }
public virtual ICollection<Aspnet_Users> Aspnet_Users { get; set; }
}
public class Aspnet_Users
{
public Aspnet_Users()
{
Aspnet_Roles = new HashSet<Aspnet_Role>();
}
[Key]
public Guid UserId { get; set; }
public string UserName { get; set; }
public string LoweredUserName { get; set; }
public string MobileAlias { get; set; }
public bool IsAnonymous { get; set; }
public DateTime LastActivityDate { get; set; }
public virtual Aspnet_Membership Aspnet_Membership { get; set; }
public virtual ICollection<Aspnet_Role> Aspnet_Roles { get; set; }
}
public class StagingContext : DbContext
{
public DbSet<Aspnet_Role> Aspnet_Roles { get; set; }
public DbSet<Aspnet_Users> Aspnet_Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany()
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}
}
I added the navigation property on the WithMany extension.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany(u => u.Aspnet_Users)
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}

EF 4.1 code first still looking for old table that no longer exists

I am using Entity Framework 4.1 code first.
I had a table in the database with the name MaritalStatus. I deleted it and created a new table in its place called MaritalStatuses. Whenever I try to get all the records from the table I get an error:
Invalid object name 'dbo.MaritalStatus'.
The query that it is trying to execute is:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[IsActive] AS [IsActive]
FROM [dbo].[MaritalStatus] AS [Extent1]}
Why would it still be looking for table MaritalStatus that I deleted? Can it be possible that it is cached somewhere? I dropped the whole database and recreated it via scripts. Still no luck. Maybe it has an issue when it comes to the "es" part of the name?
Context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
}
View model (with partial properties):
public class EditGrantApplicationViewModel
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int MaritalStatusId { get; set; }
public IEnumerable<MaritalStatus> MaritalStatuses { get; set; }
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
}
Dropdown list in view for MaritalStatuses:
<td><label>Marital Status:</label> <span class="red">**</span></td>
<td>
#Html.DropDownListFor(x => x.MaritalStatusId, new SelectList(Model.MaritalStatuses, "Id", "Name", Model.MaritalStatusId), "-- Select --")
#Html.ValidationMessageFor(x => x.MaritalStatusId)
</td>
Controller:
public ActionResult Create()
{
EditGrantApplicationViewModel viewModel = new EditGrantApplicationViewModel
{
MaritalStatuses = maritalStatusService.GetAll(),
Banks = bankService.GetAll(),
AccountTypes = accountTypeService.GetAll()
};
return View(viewModel);
}
Service:
public IEnumerable<MaritalStatus> GetAll()
{
return maritalStatusRepository.GetAll();
}
Repository:
HefContext db = new HefContext();
public IEnumerable<MaritalStatus> GetAll()
{
return db.MaritalStatuses;
}
Model class:
public class MaritalStatus
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
You may have renamed the table in your database, but your Model class is still tied to the old name. You need to map the entity to the desired table name in the OnModelCreating method of your DbContext object
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MaritalStatus>().ToTable("MaritalStatuses");
}
}
Update:
Apparently EF code first has some issues with the pluralization of some table names, such as Status. Out of curiosity I tested a few others and found several which also had this same issue.
I guess this is wrong:
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
Should be:
public DbSet<MaritalStatuses> MaritalStatuses { get; set; }