I want to add a new table in my database which my MVC 5 Project generated (with tables like: adoNetRoles, adoNetUser etc..).. I want my table to have two foreign keys on a user.. here is what my POCO-class looks like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
namespace GameApp.Models
{
[Table("Invitation")]
public class Invitation
{
public string Host { get; set; }
public string Invitee { get; set; }
}
public class InvitationContext : DbContext
{
public InvitationContext()
{
if (Database.Exists())
{
Database.Initialize(true);
}
}
public DbSet<Invitation> Inv { get; set; }
}
}
I really don't know where to put this code and how to set the foreign key. I enabled CodeFirst-Migrations already and know how it works. I know how all this works if I would create my own project and database.. but the mvc5 project confuses me. Please help me because Google couldn't!
I think the "existing database" bit is throwing people. What you're calling an "existing database" seems to be simply the tables generated by Identity, as part of your application. In other words, the whole thing is Code First, but you've already done the initial migration.
The default MVC 5 project with individual auth gives you, among other things, a context, ApplicationDbContext, and a user entity, ApplicationUser, out of the box. You will simply, then, just extend these. Namely, you will add a new DbSet to ApplicationDbContext, rather than creating a new context (InvitationContext). Generally speaking, one context == one database. If you want Invitation and ApplicationUser to interact, then they both need to be in the same context. Then, you will add a foreign key(s) to Invitation. If I understand the relationship: user has many invitations (as host) and invitation has one host, and user has many invitations (as invitee) and invitation has one invitee. In other words, you've got two foreign keys to a "user" per invitation, resulting in two separate one-to-many relationships to the same table.
public class Invitation
{
[Key]
public int Key { get; set; }
[ForeignKey("Host")]
public string HostId { get; set; }
public virtual ApplicationUser Host { get; set; }
[ForeignKey("Invitee")]
public string InviteeId { get; set; }
public virtual ApplicationUser Invitee { get; set; }
}
Assuming you already know how Code-first migrations works here what is missing for your code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace GameApp.Models
{
[Table("Invitation")]
public class Invitation
{
[Key]
public int Key { get; set; }
public string Host { get; set; }
public string Invitee { get; set; }
}
public class InvitationContext : DbContext
{
public InvitationContext() : base("YourConnectionString")
{ }
public DbSet<Invitation> Inv { get; set; }
}
}
I highly recomend you to separate tables and context in diferent files for better maintainability.
Understanding what I did now:
//I don't think you need this line and if you need it the condition should have a !
if (Database.Exists())
{
Database.Initialize(true);
}
//The constructor of DbContext can be empty, but it facilitates your work if you pass the connection string
public InvitationContext() : base("YourConnectionString")
//Use the anotation Key say to code-first migrations what is your, well, your key. Se set one key and then migrate your database.
[Key]
public int Key { get; set; }
It mostly problems with code-first than MVC, just some adjusts and you're ready to go.
source: http://www.dotnet-tricks.com/Tutorial/entityframework/R54K181213-Understanding-Entity-Framework-Code-First-Migrations.html
Related
I am trying to force a relationship in code where it does not exist in the database. I don't have the option to redefine the database. Below are the classes generated by EF.
For each survey, there are one or form elements. That is defined in the database and comes through in the classes. For each form element, there are zero, one, or more sub elements with each type being specific to it's own table. For example, if the ElementType is 'header' than the look up needs to hit the SurveyFormHeaderElement table where the SurveyFormHeaderElement.SurveyFormHeaderElementID is equal to SurveyFormElement.ElementID. There are other tables as well for prompts and lookups with the SurveyFormElement.ElementType indicating which table to do the lookup in.
I'd like to define this in the partial classes I am using for metadata so they don't get overwritten when the model updates.
// generated code
namespace Surveys.EF.Models
{
using System;
using System.Collections.Generic;
public partial class Survey
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Survey()
{
this.SurveyFormElements = new HashSet<SurveyFormElement>();
}
public int SurveyID { get; set; }
public string SurveyTitle { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SurveyFormElement> SurveyFormElements { get; set; }
}
}
// generated code
namespace Surveys.EF.Models
{
using System;
using System.Collections.Generic;
public partial class SurveyFormElement
{
public int SurveyFormElementID { get; set; }
public int SurveyID { get; set; }
public string ElementType { get; set; }
public int ElementID { get; set; }
public int ElementOrder { get; set; }
public virtual Survey Survey { get; set; }
}
}
//generated code
namespace Surveys.EF.Models
{
using System;
using System.Collections.Generic;
public partial class SurveyFormHeaderElement
{
public int SurveyFormHeaderElementID { get; set; }
public string HeaderType { get; set; }
public string HeaderText { get; set; }
}
}
// meta
namespace Surveys.EF.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(SurveyFormElementMetaData))]
public partial class SurveyFormElement
{
private ICollection<SurveyFormHeaderElement> _HeaderElements;
public virtual ICollection<SurveyFormHeaderElement> HeaderElements
{
get { return _HeaderElements; }
set { _HeaderElements = ?; } //assuming this would pull from SurveyFormHeaderElement dbcontext where SurveyFormHeaderElementID equals this.ElementID
}
}
public class SurveyFormElementMetaData
{
}
}
You would have to build an aggregate table:
So lets say you have:
Survey
PK : 1
Name "Survey 1".
And
SurveyHeaderType
Pk : 1
Name : "Header"
SurveryFooterType
Pk : 1
Name "Footer"
Survery_Type_Aggregate
PK : 1
SurveyFooterTypeId : 1
SurveryHeaderTypeId : null
But this is only required IF you can have multiple Types on 1 survey, if you can ONLY have one type on a survey, you need to create a relationship to EACH type, and just have all but 1 be null.
So becomes
Survey
PK : 1
SurveyTypeHeaderId : 1
SurveyTypeFooterId : null
Survey
PK : 2
SurveyTypeHeaderId : null
SurveyTypeFooterId : 1
But a relationship can only be created between two tables. By linking two values on said table.
I am not aware that it is possible to create a relationship between multiple tables where it can "option" out which table you are referencing. A relationship is always a contract between two tables.
The relationship between survey and header cannot, for example, reference footer, also.
You can create a relationship between footer and survey, but it would have to be on an independent value pair.
You can make a relationship value optional, but allowing the FK value to be null.
Then that just means you have no matching row of that type.
And then you have to check all references if they are not null, to find the type.
But it depends if you can have multiple types on a survey.
As far as I know, what you want to do cannot be done, because a "relationship" is limited to two tables at all times.
You can of course have multiple relationships between many, many tables.
But a relationship, can only be between two tables, again, as far as I know.
I have a connection to PostgreSQL using Entity Framework.
When retrieving data, everything works okay, also migrations are working well, the problem is during insertion of the data.
I assume its due to the ID not being automatically generated, but since I'm new to Entity Framework, I do not know how to move forward.
Here is my AddUser function:
public Task<EntityEntry<UserModel>> AddUser(UserModel user) => this.context.Users.AddAsync(user);
This is the corresponding model class:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WishareIntegrationApi.Entities
{
public class UserModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string token { get; set; }
public string displayName { get; set; }
public string photoURL { get; set; }
public string email { get; set; }
public DateTime registeredAt { get; set; }
public string birthday { get; set; }
}
}
When I add data into table manually and fill in the ID it will insert the data, if the ID is not part of the insert query, it will fail even tho it should be auto_increment.
The database is generated from the code using migrations.
Any ideas?
As Evk stated, I was missing call of the SaveChanges function.
I'm relatively new to using mvc, I have created an application with several models with scaffold controllers and CRUD views. When running my application on visual studio's local host and localdb my application works perfectly, however when trying to deploy my application I am receiving an error,
error processing your request
on the pages associated with my models.
I have deployed my project on a production iis server, and have setup a user login and database on an ms sql server. My project has the correct connection string to interact with the sql server, however when observing the database, my tables associated with my projects models are not being created - which is the route cause of the errors I am receiving.
Is anyone able to suggest why my tables are not being created; below are examples of my code, please note I am also using the asp.net Identity functionality, these tables are also not being created:
Example of one of my models:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace newwebsite.Models
{
public class Store
{
public int ID { get; set; }
public string ItemName { get; set; }
public string ItemImageName { get; set; }
public decimal ItemPrice { get; set; }
public string ItemDescription { get; set; }
public string ItemFeatures { get; set; }
}
public class StoreDBContext : DbContext
{
public DbSet<Store> Blog { get; set; }
public StoreDBContext()
: base("DefaultConnection")
{
}
public static StoreDBContext Create()
{
return new StoreDBContext();
}
}
}
Example of my connection string:
<add name="DefaultConnection" connectionString="Data Source='MSSqlServerIP'; Initial Catalog=NewWebsite2017; User ID=NewWebsite2017; Password=*****" providerName="System.Data.SqlClient" />
When I've deployed my project all views are working which suggests my controllers for these views are fine. I'm purely getting the error wherever data from the database is supposed to be shown. I believe these errors are due to my tables not being created, but am unsure why this is.
Update
I have edited the model (and others in accordingly) as follows, however still have no luck.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace newwebsite.Models
{
public class Store
{
public int ID { get; set; }
public string ItemName { get; set; }
public string ItemImageName { get; set; }
public decimal ItemPrice { get; set; }
public string ItemDescription { get; set; }
public string ItemFeatures { get; set; }
}
public class StoreDBContext : DbContext
{
public DbSet<Store> Blog { get; set; }
public StoreDBContext()
: base("DefaultConnection")
{
Database.SetInitializer<StoreDBContext>(new CreateDatabaseIfNotExists<StoreDBContext>());
}
}
}
Specify a DB initializer in your DB context
public StoreDBContext()
: base("DefaultConnection")
{
Database.SetInitializer<StoreDBContext>(new CreateDatabaseIfNotExists<StoreDBContext>());
}
There are several other initializers. e.g. DropCreateDatabaseIfModelChanges or DropCreateDatabaseAlways (be careful. this can delete your data) or you can program your own initializer.
I get the following error message when I try to add a controller for my database:
http://i.imgur.com/sYtxy3P.png
Unable to retrieve metadata for 'MvcPractise.Models.Payments'. One or more validation errors were detected during model generation.
System.Data.Entity.Edm.EdmEntityType: : EntityType 'PaymentsContext' has no key defined. Define the key for this Entity type.
Systyem.Data.Entity.Edm.EdmEntitySet:EntityType:EntitySet 'Payment' is based on the type 'Payment Context' that has no keys defined.
I am exceedingly new to Visual Studio, C# and ASP MVC.net, been following a tutorial, but slightly varying the attributes to better suit the needs for what my assignment requires.
My code looks as follows:
using System;
using System.Collections.Generic;
using System.Data;
using System.Web.Mvc;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using MvcPractise.Models;
namespace MvcPractise.Models {
public class Payments {
[Key]
public String Email { get; set; }
public String PaypalEmail { get; set; }
public String CardHoldersName { get; set; }
public String CardNumber { get; set; }
public String ExpirationDate { get; set; }
public String CardType { get; set; }
}
public class PaymentsContext : DbContext
{
public DbSet<PaymentsContext> Payment { get; set; }
public DbSet<Payments> Payments { get; set; }
}
}
If anyone can help, I've been searching through this site and trying many possible solutions, I'v recreated the database and rewritten the code, restarted VS, added the [Key] type as you can see in the code.
I believe the problem is in your PaymentsContext class. You define a DbSet Payment property which I don't think you meant to do. The PaymentsContext class is just a derived class of DbContext and shouldn't be a property of itself. The following should fix your problem:
public class PaymentsContext : DbContext
{
public DbSet<Payments> Payments { get; set; }
}
Rename class Payments to class Payment.
Then your PaymentsContext should be:
public class PaymentsContext: DbContext
{
public DbSet<Payment> Payments { get; set; }
}
I have ResorceTopices & Resources tables m to m relationship and conjunction between the 2 table. Just wondering if should I write class for conjunction or not and if I write one should be like this code?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BOL
{
class Topic_Resorsce
{
public int Id { get; set; }
public int TopicId { get; set; }
public int ResorsceId { get; set; }
}
}
Obviously, you can do it however you prefer but my answer would be no. Your classes should look like this:
public class Topic
{
public int Id { get; set; }
//whatever other fields should exist
public Resource Resource {get; set; }
}
public class Resource
{
public int Id { get; set; }
//whatever other fields should exist
}
Now you create a data access layer (or preferrably use an ORM such as EntityFramework (included in .NET), NHibernate, NHydrate, Lightspeed, etc.) that maps between your classes and your database.
Of course, there is plenty of code which has a one-for-one mapping between SQL table and POCO - so it is certainly done, I just wouldn't encourage it.