Adding a view to database created by Code First - asp.net-mvc

I have created my first ASP.NET MVC 4 application.
I have created my model which creates the Database (Database A). I now need to gather data from another database (Database B) which sits on the same server. I have created a view (2 columns - ID and Name called People) in Database A that shows me the data I require from Database B.
I'd like to add the view to my model and have typed the following
public class People
{
public int ID { get; set; }
public String Name { get; set; }
}
And added the following line to my dbContext
public class opsDBContext : DbContext
{
public DbSet<tbl_Operators> Operator { get; set; } // Existing
public DbSet<tbl_OpsWeekInfo> OperatorWeekInfo { get; set; } // Existing
public DbSet<tbl_OpsDayInfo> OperatorDayInfo { get; set; } // Existing
public DbSet<People> People{ get; set; } // New Line
}
But when i run project i get the following error
The model backing the 'opsDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
I think i understand why i get the message, i just want to me able to use the SQL View in my project, how can this be done?
Please let me know if you require more info

When a change occurs in classes of context or in your database, when you are using EF code first, you need to run migrations commands.
Take a look in this link :http://msdn.microsoft.com/en-us/data/jj591621.aspx

Related

EF Code First Cascade NULL

We have ASP MVC Entity Framework 6 Code First project with 70+ tables in a MS SQL database.
For each record on each table we are storing the user that has modified it the last. The structure of almost every table is like this:
public class TableA
{
public int Id{ get; set; }
.....
public DateTime? DateModified { get; set; }
public int? UserModifiedId { get; set; }
public virtual ApplicationUser UserModified { get; set; }
}
Our problem is we are getting an error when deleting a user if the user Id is in any of the tables' property UserModifiedId.
We need EF to set to NULL the UserModifiedId of all the tables where UserModifiedId = UserId.
In the past we setup this adding to the tables ON DELETE SET NULL, but EF doesn't allow to setup the tables like that.
Any idea how can we achieve this?
UPDATED
We already know EF manages this is the children are loaded into the context, but we can't load more than 70+ tables every time we want to delete a user.
One approach could be to add a migration that modifies all your tables that should have CASCADE ON DELTE SET NULL like that way (only for your example code above):
public partial class AddOnDeleteSetNull : DbMigration
{
public override void Up()
{
Sql("ALTER TABLE dbo.TableA DROP CONSTRAINT [FK_dbo.TableA_dbo.Users_UserModifiedId]");
Sql("ALTER TABLE dbo.TableA ADD CONSTRAINT [FK_dbo.TableA_dbo.Users_UserModifiedId_SetNullOnDelete] FOREIGN KEY (UserModifiedId) REFERENCES dbo.Users(UserId) ON UPDATE NO ACTION ON DELETE SET NULL");
}
public override void Down()
{
// Here you have to undo the changes!
// ...
}
}

Getting an EntityType has no defined key error when trying to create a view from a MVC ViewModel

I'm working on an ASP.NET MVC 5 project in which I'm trying to build a controller from a MVC View Model. That ViewModel brings together 6 tables which I need to show in the views. Its my understanding that using MVC ViewModels is one way of showing multiple tables in a view. Anyway, I'm getting the following error message:
Error
There was an error running the selected code generator: 'Unable to retrieve metadata for
'PrismSmallTasks.ViewModels.ManageInterviewVM'. One of more validation errors were
detected during model generation:
ManageInterviewVM:: EntityType 'ManageInterviewVM' has no key defined.
Define the key for this EntityType.
ManageInterviewVMs: EntityType: EntitySet 'ManageInterviewsVMs' is based on
type 'ManageInterviewVM' that has no keys defined.
There's no key in the ManageInterviewVM ViewModel. That's because it's comprised of lists of the tables represented in the models that are in the VM. And each of those model classes do have a column that has a key defined for it.
For example, here's ManageInterviewVM:
public class ManageInterviewVM
{
public List<FieldRecord> FieldRecords { get; set; }
public List<TaskList> TaskLists { get; set; }
public List<InterviewARVTreatment> InterviewARVTreatments { get; set; }
public List<Note> Notes { get; set; }
public List<Risk> Risks { get; set; }
public List<Interview1> Interviews { get; set; }
}
And here's a partial listing of one of those tables as it is defined in the model class:
public partial class TaskList
{
[Key]
public int ID_TaskList { get; set; }
[Required]
[StringLength(15)]
public string CD_TaskListType { get; set; }
public int? ID_Profile { get; set; }
public int? ID_FieldRecord { get; set; }
public int? ID_Interview { get; set; }
So, I don't know what I'm missing. Why is this error showing up and how I can resolve it?
Your ViewModels should be completely dissociated from your Data Context (Data Access Layer). Only your domain models should deal with the DAL. ViewModels are only for displaying specific information to the view.
So after you create your ViewModel.. you try and create your view. When you arrive at this screen:
Type in your view name
Pick your template (if you leave it as 'Empty (without model)' then you should be able to just create it without any issue).
Once you pick a specific template and Model class (ViewModel), the 'Data context class' will auto-populate with your connection string (dbcontext), which is where your problem lies.
Since viewmodels are not supposed to be associated with the data access layer, you can just delete what is auto-populated in the 'Data context class' and then you should be able to create your view.
If you fall into the trap of thinking that you need to define keys for your viewmodel.. then your viewmodel class will be added to your connection string's class (dbcontext class).. which is a no-no.
You need to query the database using your domain models.. then you assign those values to your ViewModels properties that you want to display.
Hope this helps!

ASP.net MVC - Master Detail - foreign key is always zero

I'm new to MVC and trying to add/ edit records in master detail form. Both masterid and detailid are generated by oracle on insert of record. Thus when I try to call DBContext.SaveChanges() I get error that foreign key is violated and no primary row with id '0' can be found.
Below is the class description.
public class Master
{
public int MasterID { get; set; }
public string MasterTitle { get; set; }
public virtual IList<Detail> Details { get; set; }
}
public class Detail
{
public int DetailID { get; set; }
public int MasterID { get; set; }
public string DetailName { get; set; }
public virtual Master Master { get; set; }
}
Controller code
[HttpPost]
public ActionResult Create(MASTER masterrecord)
{
if (ModelState.IsValid)
{
db.MASTER.Add(masterrecord);
db.SaveChanges();
}
...
}
The primary key (masterid) will get meaningful values only after record is inserted to database. context.SaveChanges() at this point tries to save Client records too with '0' masterid. I searched every where couldn't find anything which could be of useful.
Though of saving only Master table first so that I can retrieve the masterid and us it with DETAIL model. however couldnt find anywhere how to do it using EF5 MVC ASP.NET
Can any one point me to right direction of provide with some working sample?
thanks
Siddhant
You might want to consider using GUIDs instead of ints for your PK. Then in your constructor for Master you can say MasterID = Guid.NewGuid();. This way you don't have to hit the database to find out what the next ID will be.
There is a pro and con list here http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html
If you have set a breakpoint on the Create method and are getting a proper list in your Master object, it may be an issue with the Oracle provider.
As a workaround, you could try to change the method signature to accept your data like the following:
public ActionResult Create(MASTER masterrecord, List<Detail> details)
Then you could first save the masterrecord and subsequently add your details and save again. It's not optimal, but it may work.
Side note: change your IList to an ICollection.

Retrieving related data using linq

I have an MVC app using EF code first. I add a user to the system and enter pension details, part of this is a dropdown linked to a model called PensionBenefitLevel. This is the model -
[Key]
public int PensionBenefitLevelID { get; set; }
public string DisplayText { get; set; }
public int EmployeePercentage { get; set; }
public int EmployerPercentage { get; set; }
public virtual ICollection<Pension> Pension { get; set; }
When registered I have the PensionBenefitLevelID that came from the dropdown, but in my controller I was to peform a calculation using the EmployerPercentage value that is related to that ID. Can anyone point me in the correct direction?
Do I need to create a variable in the controller and use a linq query to get that value back? I've not been able to find any examples of something similar so if you could point me to one that would be great too.
If I understand the question correctly, you want to get back the entity corresponding to PensionBenefitLevelID and perform a calculation on the EmployerPercentage field.
Since you haven't mentioned what pattern you are using with EF (repository, unit of work, etc.) I can only give you a general answer:
var entity = [Your DB Context].[Your Entity].GetById(pensionBenefitLevelID);
if(entity != null)
{
[Calculation]
}

Establish Foreign Key Connection Using Entity Framework With SQL Queries

I have a couple of classes (for this example anyway) that use code first with the entity framework to connect to the database.
public class Customer
{
[Key]
public long CustomerId { get; set; }
public string CompanyName { get; set; }
...
public virtual List<Contact> Contacts { get; set; }
}
public class Contact
{
[Key]
public long ContactId { get; set; }
public string Forename { get; set; }
...
public long CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
When I hook these up in my context class directly to the db the foreign key relationships hook up fine and I can access the collection of contacts from within the customer class.
class RemoteServerContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Contact> Contacts { get; set; }
...
}
My problem is that these database tables are used by various different systems and are massive. In order to increase efficiency I have overridden the default behaviour to point at a view (and also a stored proc elsewhere) rather than directly at the table.
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
public IEnumerable<Contact> Contacts()
{
return Database.SqlQuery<Contact>("SELECT * FROM vw_ContactsList");
}
I have made sure that in each of the views I have included the foreign key fields: CustomerId and ContactId.
When I do this however the class joins appear to be lost - there's always a null when I drill into either of the objects where it should be pointing to the other one. I have tried to set up what the foreign key field should point to but this doesn't seem to help either.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>().HasRequired(p => p.Customer)
.WithMany()
.HasForeignKey(k => k.CustomerId);
}
Is there a way to establish the connection when overriding the default behaviour?
There is no overriding in this case. If you removed
public DbSet<Customer> Customers { get; set; }
and replaced it with
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
you have completely changed the behavior. The first uses entities and full power of EF. The second is only helper to execute custom SQL. Second without first or without defining entity in OnModelCreating doesn't use Customer as mapped entity at all - it uses it as any normal class (only mapped entities can use features like lazy loading).
Because your Customer is now mapped to view you cannot use your former Customer class used with table. You must define mapping of Customer to a view by cheating EF:
modelBuilder.Entity<Customer>().ToTable("vw_ContactsList"); // EF code fist has no view mapping
Once you have this you can try again using:
public DbSet<Customer> Customers { get; set; }
Unless your view is updatable you will get exception each time you try to add, update or delete any customer in this set. After mapping relation between Customer and Contact mapped to views your navigation properties should hopefully work.
The problem with SqlQuery is the way how it works. It returns detached entities. Detached entities are not connected to the context and they will not lazy load its navigation properties. You must manually attach each Customer instance back to context and to do that you again need DbSet.

Resources