How to make changes in Database First code to make it working with Code First - asp.net-mvc-4

i am having trouble in changing code from database first to code first.I was implementing this blog post http://techbrij.com/facebook-wall-posts-comments-knockout-aspnet-webapi.
First trouble is with database generated from code first.It is creating two User Profile tables in database.First is singular and another is Plurized.
Singular one (UserProfile table)is created while registering(Simple membership used).
My Post class is something like this----
public class Post
{
public Post()
{
this.PostComments = new HashSet<PostComment>();
}
[Key]
public int PostId { get; set; }
public string Message { get; set; }
public int PostedBy { get; set; }
public System.DateTime PostedDate { get; set; }
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile UserProfile { get; set; }
public virtual ICollection<PostComment> PostComments { get; set; }
}
}
and my Post Comment class is something like this----
public class PostComment
{
[Key]
public int CommentId { get; set; }
public int PostId { get; set; }
public string Message { get; set; }
public int CommentedBy { get; set; }
public System.DateTime CommentedDate { get; set; }
public virtual Post Post { get; set; }
public virtual UserProfile UserProfile { get; set; }
}
and my UserProfile class is like this----
public class UserProfile
{
public UserProfile()
{
this.PostComments = new HashSet<PostComment>();
this.Posts = new HashSet<Post>();
}
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
public string AvatarExt { get; set; }
public virtual ICollection<PostComment> PostComments { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
and My DbContext is something like this---
public class WallEntitiesDbContext : DbContext
{
public WallEntitiesDbContext():base("WallEntitiesDbContext")
{
}
public DbSet<PostComment> PostComments { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }
public override int SaveChanges()
{
return base.SaveChanges();
}
}
and my connection string are like this----
<add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=DBWallPostByTechBrij;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
what changes should i made so that only one UserProfile table is created in database and WallEntitiesDbContext should be able to retreive information from that table in database.
Right now, If i remove------
DbSet<UserProfile> UserProfiles {get; set;}
then i start getting error in my wallpostController. If anyone could help me in getting this working with code First then it would be great help.One more thing,I have manually entered some sample data into database so, after login it should show posts and comments from database but it's not showing and if i tried to post something, it throws exception System.Data.Infrastructure.DbUpdateException at this line----
public override int SaveChanges()
{
return base.SaveChanges();
}
in WallEntitiesDbContext class.
Plzzz anyone have a look it.What changes should i make to make it working.

I think there is no need for two dbContext as u are implementing from the article.
So, use only one dbcontext like this----
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfile { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<PostComment> PostComments { get; set; }
In DbFisrt approach as in article, u may use it but in code first approach, definitly two dbcontext will create two userProfile table.
Nothing more is needed to be changed.

Related

How to establish one-to-many relationship for a code-first approach?

I'm trying to build a recipe app for my spouse. I'm trying to set it up so she can add new recipes to the database as the app grows.
When adding new recipe, she will have three drop-down to pick from to construct her new recipe ingredients. First one will contain a list of ingredients that she can choose from, the second one a list of measuring units and the third one a list of quantities.
Here is what I got so far. Am I heading in the right direction or am I off? I'm using Entity Framework with a code-first approach:
public class Recipes
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
public class Units model
{
[Key]
public int Id { get; set; }
public string UnitName { get; set; }
}
public class UnitQty
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class IngredientsModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class RecipeIngredients
{
public int Id { get; set; }
public int RecipesId { get; set; }
[ForeignKey("RecipesId")]
public Recipes Recipes { get; set; }
public int IngredientsModelId { get; set; }
[ForeignKey("IngredientsModelId")]
public IngredientsModel IngredientsModel { get; set; }
public int UnitQtyId { get; set; }
[ForeignKey("UnitQtyId")]
public UnitQty UnitQty { get; set; }
public int UnitsModelId { get; set; }
[ForeignKey("UnitsModelId")]
public UnitsModel UnitsModel { get; set; }
}
After creating the table, controller and the views, this is what I get in the recipe ingredients index view.
Any suggestion will be more than welcome please and thank you
RecipeIngredient class's view
First of all. You are over engineering your domain model. On relational databases Join is bottleneck you should prevent from joins if it doesn't helps you.
public class Recipt
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public ICollection<RecipeIngredient> Ingredients { get; set; }
}
public class IngredientModel
{
public int Id { get; set; }
public string Name { get; set; }
public IngredientUnit UnitType { get; set; } // Unit model is best to be added here. if it doesn't change in a single IngredientModel.
}
public class RecipeIngredient
{
public int Id { get; set; }
public int UnitQuantiy { get; set; } // No need to more classes.
public IngredientModel Model { get; set; }
public Recipt Recipt { get; set; }
}
public Enum IngredientUnitType // Same Unit Model but less database relation as its small finite collection.
{
Killogram,
Count,
....
}
and according to the Microsoft documents its best to use fluentApi configuration for the relations.
Override this method in your Context:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Recipt>.HasMany(P => P.Ingredients).WithOne(P => P.Recipt);
builder.Entity<RecipeIngredient>.HasOne(P => P.Model);
// There is no need to explicit foreign key definition. but you can explicitly define your foreign keys.
}
And for the last part. in Views you can use extra models called ViewModels.
As above domain turned to a minimal domain you just need to pass a list of IngredientModels to your view to complete your View.

How to configure One to Many relationship in Entity Framework

I am creating API in ASP .NET Core that will retrieve posts with user Id. Post should contain text and Id of a user who posted it.
I have two models Users and Posts and I need help on how to configure this relationship
I want one User to have many posts
Currently my user model contains
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public List<Post> Posts { get; set; }
}
And my Post model
public class Post
{
public int Id { get; set; }
public string Text { get; set; }
}
What is the best way to do this ?
One to many relationships ( User to have many posts).
public class User{
public int Id { get; set; }
public string Username { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Text { get; set; }
//Navigation
public int UserId { get; set; }
public User User{ get; set; }
}
this is your Model Class:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public Virtual List<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Text { get; set; }
public int UserId { get; set; }
public Virtual User User { get; set; }
}
and in your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<User>().HasMany(x=>x.Posts).WithRequired(x=>x.User)
.HasForeignKey<int>(s => s.UserId);
}

Is it possible to link one table to another with entity framework core without FKs?

I have 2 tables company and user. Company will have one created by user and one modified user - these will be admin users. User will belong to one company but one admin user could create or modify multiple companies.
I'm having a hard time using entity framework core in my .net core app to join company and user so when I get a company record I have the created by and modified user information.
My company and user classes look like this:
public class Company
{
[Key]
public Guid Id { get; set; }
public DateTime Created { get; set; }
public Guid Created_By { get; set; }
public virtual ApplicationUser CreatedByUser { get; set; }
public DateTime Modified { get; set; }
public Guid Modified_By { get; set; }
public virtual ApplicationUser ModifiedByUser { get; set; }
public string Company_Name { get; set; }
}
public class ApplicationUser: IdentityUser<Guid>
{
[Column("ID")]
public override Guid Id { get; set; }
[Column("CREATED")]
public DateTime Created { get; set; }
[Column("CREATED_BY")]
public Guid? CreatedBy { get; set; }
[Column("MODIFIED")]
public DateTime Modified { get; set; }
[Column("MODIFIED_BY")]
public Guid? ModifiedBy { get; set; }
[Column("FIRST_NAME")]
public string FirstName { get; set; }
[Column("LAST_NAME")]
public string LastName { get; set; }
[Column("EMAIL")]
public override string Email { get; set; }
[Column("NORMALIZED_EMAIL")]
public override string NormalizedEmail { get; set; }
[Column("EMAIL_CONFIRMED")]
public override bool EmailConfirmed { get; set; }
[Column("USER_NAME")]
public override string UserName { get; set; }
[Column("NORMALIZED_USER_NAME")]
public override string NormalizedUserName { get; set; }
[Column("COMPANY_ID")]
public Guid CompanyId { get; set; }
[Column("PHONE_NUMBER")]
public override string PhoneNumber { get; set; }
[Column("PHONE_NUMBER_CONFIRMED")]
public override bool PhoneNumberConfirmed { get; set; }
[Column("TITLE")]
public string Title { get; set; }
[Column("ACTIVE")]
public bool Active { get; set; }
[Column("ROLE_ID")]
public int UserRoleId { get; set; }
[Column("TYPE_ID")]
public int TypeId { get; set; }
[Column("PASSWORD_HASH")]
public override string PasswordHash { get; set; }
[Column("SECURITY_STAMP")]
public override string SecurityStamp { get; set; }
[Column("CONCURRENCY_STAMP")]
public override string ConcurrencyStamp { get; set; }
[Column("TWO_FACTOR_ENABLED")]
public override bool TwoFactorEnabled { get; set; }
[Column("LOCKOUT_END")]
public override DateTimeOffset? LockoutEnd { get; set; }
[Column("LOCKOUT_ENABLED")]
public override bool LockoutEnabled { get; set; }
[Column("ACCESS_FAILED_COUNT")]
public override int AccessFailedCount { get; set; }
}
My DbContext class looks like this:
public class DbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid, ApplicationUserClaim, ApplicationUserRole, IdentityUserLogin<Guid>, IdentityRoleClaim<Guid>, IdentityUserToken<Guid>>
{
public DbContext(DbContextOptions<DbContext> options) : base(options)
{
}
public virtual DbSet<Company> Companies { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Company>().ToTable("COMPANY").Property<Guid>("Created_By");
builder.Entity<Company>().HasOne(x => x.CreatedByUser).WithOne().HasForeignKey("Created_By");
builder.Entity<ApplicationUser>().ToTable("USER");
builder.Entity<ApplicationUser>().HasKey(x => x.Id);
builder.Entity<ApplicationUserClaim>().ToTable("USER_CLAIMS");
builder.Entity<ApplicationRole>().ToTable("IDENTITY_ROLES");
builder.Entity<IdentityUserRole<Guid>>().HasKey(p => new { p.UserId, p.RoleId });
builder.Entity<ApplicationUserRole>().ToTable("IDENTITY_USER_ROLES");
}
}
And I was trying to get companies like this:
public async Task<List<Company>> GetAllCompanies()
{
return await _locationDbContext.Companies.ToListAsync();
}
Currently I am getting this error:
System.InvalidOperationException: 'You are configuring a relationship between 'Company' and 'ApplicationUser' but have specified a foreign key on 'Created_By'. The foreign key must be defined on a type that is part of the relationship.'
Is there an easier way to do this? Really all I want is the username of the user that created of modified the company record? If I was doing this with just sql I would just use a basic Join but Im not sure how to do that with entity framework. Worst case I would just get all the companies and then loop through doing a select on the user table where ID = Created_By
As #IvanStoev noticed without FKs it is not possible. But you can still use EF to join 2 tables.
In your case you have to unmap user from company and maybe it is a good idea to make user Guid nullable:
public class Company
{
[Key]
public Guid Id { get; set; }
public string Company_Name { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public Guid Created_By { get; set; }
public Guid Modified_By { get; set; }
[NotMapped]
public ApplicationUser CreatedByUser { get; set; }
// or better
[NotMapped]
public string CreatedByUser { get; set; }
[NotMapped]
public ApplicationUser ModifiedByUser { get; set; }
//or better
[NotMapped]
public string ModifiedByUser { get; set; }
}
and remove
builder.Entity<Company>().HasOne(x => x.CreatedByUser).WithOne().HasForeignKey("Created_By");
you still can join them like this
var companies= (
from c in _locationDbContext.Companies
join uc in _locationDbContext.ApplicatonUser on c.Created_By equals uc.Id
join um in _locationDbContext.ApplicatonUser on c.Modified_By equals um.Id
select new Company
{
....
CreatedByUser = uc,
ModifiedByUser = um
// or usually
CreatedByUser = uc.FirstName + " " + uc.LastName,
ModifiedByUser = um.FirstName + " " + um.LastName,
}).ToList();
This is one way of accomplishing this.
This is a simplified version of class Company:
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
//
// Relations
public string CreatorID { get; set; }
public ApplicationUser Creator { get; set; }
public string LastModifiedByID { get; set; }
public ApplicationUser LastModifiedBy { get; set; }
}
CreatorID and LastModifiedByID will be used by EF for determining the FK's. These are the fields you have to work with when updating the Db, not Creator and LastModfiedBy, yet you can also do it but with more lines of code.
Now, you can add companies the usual way, this code searches for the company, and creates one if not found, just sample code, not serious, really:
var companyName = "My company";
var company = context.Companies.Include(c => c.Creator).Include(c => c.Creator).FirstOrDefault(c => c.Name == companyName);
if (company == null)
{
company = new Company
{
Name = "My company",
CreatorID = user.Id,
LastModifiedByID = user.Id
};
context.Companies.Add(company);
context.SaveChanges();
}
And retrieving the companies with all relations filled is a matter or using calls to Include() and ThenInclude(), like here:
var companies = context.Companies.Include(c => c.Creator).Include(c => c.Creator).ToList();
I omitted all filtering logic for the sake of simplicity.

Asp Core Multiple Entity Relationships

I am working on modeling a Contact Info Structure and haven't quite figured out how the relationships should be coded with EF Core. I am fairly new to using EF for data access layer.
I want to have a contact model which can contain Website, Phonenumbers, Emails, or Social Info. Then the contact info will be added to several different models. Any suggestions would be helpful, I am not sure how code this One to many with many table relationship or if it is even possible using EF.
Models so far
public class Contact
{
public String Id { get; set; }
public Int32 ContactType { get; set; } //Enum for Website, Phonenumbers, Emails, or Social
public String RecId { get; set; } //FK to multiple Models
public String RecType { get; set; }//Value for which model the RecID is for
public String Name { get; set; }
public String Value { get; set; }
}
public class ContactInfo
{
public virtual IList<Contact> Website { get; set; }
public virtual IList<Contact> PhoneNumbers { get; set; }
public virtual IList<Contact> Emails { get; set; }
public virtual IList<Contact> Socials { get; set; }
}
//Example of models to use the contact model
public class Company
{
....
pubic ContactInfo ContactInfo { get; set;}
}
public class Client
{
....
pubic ContactInfo ContactInfo { get; set;}
}
If I understand your question correctly, then you could use following code sample, but it is not exactly what you are trying to achieve. This may give you some understanding what you need to do with EF.
public class Contact
{
public String Id { get; set; }
public ContactType ContactType { get; set; } //Enum for Website, Phonenumbers, Emails, or Social
public String RecId { get; set; } //FK to multiple Models (This can't be the FK to multiple table as it should be FK for one table so that FK for Company would be CompanyId, FK for the Client should ClientId)
public String RecType { get; set; }//Value for which model the RecID is for (This need to rethink as it may not needed.)
public String Name { get; set; }
public String Value { get; set; }
// One to Many Relationship
public string CompanyId? { get; set; }
public string ClientId? { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class Company
{
public String Id { get; set; }
// Other properties
// One to Many Relationship
public ICollection<Contact> Contacts { get; set; }
}
public class Client
{
public String Id { get; set; }
// Other properties
// One to Many Relationship
public ICollection<Contact> Contacts { get; set; }
}
/* Db context */
public class YourDbContext : DbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options)
: base(options)
{
}
public virtual DbSet<Contact> Contacts { get; set; }
public virtual DbSet<Company> Companies { get; set; }
public virtual DbSet<Client> Clients { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Contact>().HasKey(t => t.Id);
modelBuilder.Entity<Company>().HasKey(t => t.Id);
modelBuilder.Entity<Company>().HasMany(c => c.Contacts).WithOne(c => c.Company).HasForeignKey(k => k.CompanyId);
modelBuilder.Entity<Client>().HasKey(t => t.Id);
modelBuilder.Entity<Client>().HasMany(t => t.Contacts).WithOne(c =>c.Client).HasForeignKey(k => k.ClientId);
}
}
/* Db context - Endd */
public enum ContactType
{
Website,
PhoneNumbers,
Emails,
Social
}
Let me know if you need anymore information.
With the help from DSR, this is the solution I have (untested).
public class Company
{
public String Id { get; set; }
public String Name { get; set; }
public ICollection<ContactPhone> PhoneNumbers { get; set; }
public ICollection<ContactEmail> ContactEmail { get; set; }
public ICollection<ContactWebsite> ContactWebsite { get; set; }
public ICollection<ContactSocial> ContactSocial { get; set; }
}
public class Client
{
public String Id { get; set; }
public String Name { get; set; }
public ICollection<ContactPhone> PhoneNumbers { get; set; }
public ICollection<ContactEmail> ContactEmail { get; set; }
public ICollection<ContactWebsite> ContactWebsite { get; set; }
public ICollection<ContactSocial> ContactSocial { get; set; }
}
public class ContactWebsite
{
public String Id { get; set; }
public String Url { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactPhone
{
public String Id { get; set; }
public String Type { get; set; }
public String Number { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactEmail
{
public String Id { get; set; }
public String Category { get; set; }
public String Email { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactSocial
{
public String Id { get; set; }
public String Site { get; set; }
public String Handle { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}

CodeFirst - Update single property

We are using EF5, Code First approach to an MVC4 app that we're building. We are trying to update 1 property on an entity but keep getting errors. Here's what the class looks like which the context created:
public partial class Room
{
public Room()
{
this.Address = new HashSet<Address>();
}
public int RoomID { get; set; }
public Nullable<int> AddressID { get; set; }
public Nullable<int> ProductVersionID { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string RoomName { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Notes { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
Here's our ViewModel for the view:
public class RoomDetailsViewModel
{
//public int RoomID { get; set; }
public string RoomName { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string Notes { get; set; }
public string StateCode { get; set; }
public string CountryName { get; set; }
public string ProductVersion { get; set; }
public int PVersionID { get; set; }
public List<SelectListItem> ProductVersions { get; set; }
public Room Room { get; set; }
}
Here's the Controller Action being called on "Save":
[HttpPost]
public virtual ActionResult UpdateRoom(RoomDetailsViewModel model)
{
var db = new DBContext();
bool b = ModelState.IsValid;
var rooms = db.Rooms;
var rm = rooms.Where(r => r.RoomID == model.Room.RoomID).Single();
//List<Address> address = db.Addresses.Where(a => a.AddressID == rm.AddressID).ToList<Address>();
rm.ProductVersionID = model.PVersionID;
//rm.Address = address;
db.Entry(rm).Property(r => r.ProductVersionID).IsModified = true;
//db.Entry(rm).State = System.Data.EntityState.Modified;
db.SaveChanges();
return View("RoomSaved", model);
}
All this view does is display data and allow the user to change the Product Version (from a SelectList), so, in the Room Entity, all we are updating is the ProductVersionID property, nothing else. We can get the data to display properly but when we click "save", we get this error:
An object of type 'System.Collections.Generic.List`1[[Models.Address,
Web.Mobile.TestSite, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]' cannot be set or removed from the Value
property of an EntityReference of type 'Models.Address'.
As you can see by the Controller Action, we've tried several different things but all seem to produce this error. I've tried to populate the model.Room.Address collection with an Address, without, but still get this error.
I read this StackOverflow article and this article as well but neither have solved my problem.
ANY help with this would be greatly appreciated!
After hours and hours of digging, turns out that EF did not import some of the PK's for my DB tables. What tipped me off to this was on the Room class, the PK RoomID did not have the [Key] attribute on it. I tried to reimport the table through the edmx but it never came through as a key (even though it's clearly marked PK in the DB). So, to get around it, I created a partial class of my DBContext and override the OnModelCreating event and included the key, like so:
public partial class DBContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Models.Room>().HasEntitySetName("Rooms");
modelBuilder.Entity<Models.Room>().HasKey(r => r.RoomID);
}
}
Once this was done, the Action saved the record as hoped.
I hope this helps someone else!