Seed() not fully updating the database - c#

I'm giving a go through some tutorials (here and here) on ASP.NET MVC, and decided to try a few things on my own. Now, I've got three tables, Resume, Descriptions, SubDescriptions. Here's the code for the three:
public class Resume
{
public Resume()
{
Descriptions = new List<Description>();
}
[Key]
public int ResumeId { get; set; }
[Required]
public string Employer { get; set; }
[DataType(DataType.Date)]
public DateTime StartDate { get; set; }
[DataType(DataType.Date)]
public DateTime EndDate { get; set; }
[Required]
public string Location { get; set; }
[Required]
public virtual ICollection<Description> Descriptions { get; set; }
}
public class Description
{
public Description()
{
SubDescriptions = new List<SubDescription>();
}
[Key]
public int DescriptionId { get; set; }
[ForeignKey("Resume")]
public int ResumeId { get; set; }
[Required]
public string Desc { get; set; }
public virtual Resume Resume { get; set; }
public virtual ICollection<SubDescription> SubDescriptions { get; set; }
}
public class SubDescription
{
[Key]
public int SubDescriptionId { get; set; }
[ForeignKey("Description")]
public int DescriptionId { get; set; }
[Required]
public string Sub { get; set; }
public virtual Description Description { get; set; }
}
And my Seed() is as follows:
protected override void Seed(ResumeDBContext context)
{
context.Resumes.AddOrUpdate(i => i.Employer,
new Resume
{
Employer = "Employer Test",
StartDate = DateTime.Parse("2012-3-26"),
EndDate = DateTime.Parse("2013-10-24"),
Location = "Houston, TX",
Descriptions = { new Description
{ Desc = "DescTest",
SubDescriptions = {new SubDescription {Sub = "SubTest"},
new SubDescription {Sub = "SubTest2"},
new SubDescription {Sub = "SubTest3"}}
},
new Description { Desc = "DescTest2" }}
}
);
}
Now, whenever I run update-database from my Package Manager Console, it says it's running Seed(). However, upon querying the database, my SubDescriptions table is still empty. Everything else populates as expected. I don't receive any errors, or anything of the sort. Am I missing something silly in my associations?
The Resume table is populated properly from the Seed(), and the Descriptions table is populated as well, with the appropriate association to the Resume table. Yet, following the same example to try to populate SubDescriptions, the table is just flat out empty. The associations and navigation properties appear to be set correctly, but as I'm new to this, I'm not 100% certain.

Okay, so I found the answer quite by accident. I dropped and recreated the database, and when it ran Seed() again, it populated all my tables as it should. Initially, I was making changes to the Seed() and updating, hoping that they'd be applied. But since the data already existed in the tables, it wasn't populating.

Related

How to update a table of an existing, scaffolded database in ASP.NET Core

I scaffolded my database succesfully, and I tried adding a field to a model
`
public partial class Cotizaciones
{
private static Random rnd = new Random();
public Cotizaciones()
{
DetalleProductoPersonalizados = new HashSet<DetalleProductoPersonalizado>();
}
[Key]
public int Idcotizacion { get; set; }
public DateTime FechaInicio { get; set; }
public DateTime FechaFin { get; set; }
public double PrecioFinal { get; set; }
public string Ubicacion { get; set; } = null!;
public bool Estado { get; set; }
public int? PaqueteFk { get; set; }
[Column(TypeName = "nvarchar(max)")]
public string? NombreCotizacion = GenerateLetter(); //---> new field
private static string GenerateLetter()
{
StringBuilder fileName = new StringBuilder("");
for (int i = 0; i <= rnd.NextInt64(1,35); i++)
{
fileName.Insert(i, Convert.ToChar(rnd.Next(65, 90)));
}
return fileName.ToString();
}
[NotMapped]
[DisplayName("Subir comprobante de pago")]
public IFormFile ImageFile { get; set; }
public virtual Paquete? PaqueteFkNavigation { get; set; }
public virtual ICollection<DetalleProductoPersonalizado> DetalleProductoPersonalizados { get; set; }
}
`
However applying migrations said no changes were made, making a new migration and trying to apply it throws me this message
There is already an object named 'AspNetRoles' in the database.
You are mixing Model stuff, with business logic, and EF will not allow this. You would need to take the "GenerateLetter" piece and move it to a different process, and make your new addition a true property.
You could possibly use a [Backing Fields][1] implementation to try and get this working, but it will not do what I think you might think it would do.
You will most likely have to re-think how that GenerateLetter method is called if you want to persist the value to the database. You could possibly make it a [computed column][1], but you wouldn't have access to Random etc. there.

How to create list of object as foreign keys in Entity Framework and fill the database

I'm new to Entity Framework and I'm trying to create database for my Android application using Entity Framework with a code-first approach (I think).
My database would look like this:
In the Restaurant table, I would like to have a list of Dish table elements and same for Groceries in the Dish table.
I tried to do it like this:
https://entityframework.net/knowledge-base/41048304/entity-framework-class-with-list-of-object
But I can't see the FK in migration or in the database.
Next I tried it like this code below (here are my classes) :
public class Restaurant
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IdRestaurant { get; set; }
[Required]
public String NameOfRestaurant { get; set; }
[Required]
public String Location { get; set; }
[Required]
public String PictureOfRestaurant { get; set; }
public virtual ICollection<Dish> Dishes { get; set; }
[Required]
public String UserId { get; set; }
public ApplicationUser User { get; set; }
}
public class Dish
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IdDish { get; set; }
[Required]
public String NameOfDish { get; set; }
[Required]
public String PictureOfDish { get; set; }
[Required]
public Double Price { get; set; }
[Required]
public Double CalorieValue { get; set; }
public virtual int? IdRestaurant { get; set; }
public virtual Restaurant Restaurant { get; set; }
public virtual ICollection<Grocery> Groceries{ get; set; }
[Required]
public String UserId { get; set; }
public ApplicationUser User { get; set; }
}
public class Grocery
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IdGrocery { get; set; }
[Required]
public String NameOfGrocery { get; set; }
[Required]
public String PictureOfGrocery { get; set; }
[Required]
public Double CalorieValue { get; set; }
public virtual int? IdDish { get; set; }
public virtual Dish Dish { get; set; }
[Required]
public String UserId { get; set; }
public ApplicationUser User { get; set; }
}
But it didn't work.
After I solve this problem, I would like to add some elements in database. Tried it like this (just to test if it works, but with no success) :
internal sealed class Configuration : DbMigrationsConfiguration<Restaurants.Models.MojDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(Restaurants.Models.MojDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.Groceries.AddOrUpdate(x => x.IdGrocery,
new Grocery()
{
NameOfGrocery = "Carrot",
PictureOfGrocery = "anhnahdagd",
CalorieValue = 55
},
new Grocery()
{
NameOfGrocery = "Tomato",
PictureOfGrocery = "wqeqwewqeewqqew",
CalorieValue = 89
},
new Grocery()
{
NameOfGrocery = "Potato",
PictureOfGrocery = "zuuuiitutuitu",
CalorieValue = 110
}
);
context.SaveChanges();
}
}
And when I add a migration with:
Add-Migration SeedMigration
it just creates a blank migration :
public partial class SeedMigration : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
So how can I add data into the table?
Create foreign key
To create a foreign key, you have to add a line that is an [Index], with a name (in this example) U_FK and then add [Required] at the end.
[Index]
public int U_FK { get; set; } // Foreign Key - User
[Required]
Create list of foreign key
To create a foreign key, you have to add a line that is an [Index], with a name (in this example) U_FK and then add [Required] at the end.
[Index]
public List<int> U_FK { get; set; } // Foreign Key - User List
[Required]
Add elements to database
To add elements you first call the class name and create a new instance of it, in this case exp. Then you assign it's values (as long as they aren't required you don't have to). After that you load your context and save it in ExampleList you created (will show example below).
Example exp = new Example
{
Active = true,
Titel = InputTitel,
Views = 0,
};
using(var context = new ForumDbContext())
{
context.Examples.Add(exp);
context.SaveChanges();
}
Create a Context (if you don't already have one)
In your specific case you can replace Context with your already existing seed migration.
public class GlobalRef
{
public static string dbConnectionString = "Data Source = (localdb)\\MSSQLLocalDB; Initial Catalog = FForumDB; Integrated Security = True; MultipleActiveResultSets=True";
}
public class ForumDbContext : DbContext
{
public ForumDbContext() : base(GlobalRef.dbConnectionString) {}
public DbSet<Example> Examples{ get; set; }
}
Get Value from database
To get for example the ID of another Datatable. You first get the context again. Then you loop through each element in that Database where it's active and order it by views. You can also add .First() to only get the first element that was returned.
using(ForumDbContext context = new ForumDbContext())
{
foreach(Example example in context.Examples.SqlQuery("SELECT * FROM Examples WHERE Active='1' ORDER BY Views" ).ToList<Example>())
{
int exampleid = example.E_ID;
}
}
Get all Values from database and put them in a List
List<int> exampleFKs = new List<int>;
using(ForumDbContext context = new ForumDbContext())
{
foreach(Example example in context.Examples.SqlQuery("SELECT * FROM Examples WHERE Active='1' ORDER BY Views" ).ToList<Example>())
{
exampleFKs.Add(example.E_ID);
}
}

WPF Entity Framework Foreign key won't load it's value in a DataGrid

I am using Entity Framework code first with fluent API I have an items table with foreign keys from users and units tables
but when I load the table to ObservableCollection then bind it to a datagrid the table normal column load it's data normally into the datagrid excpet for the foreign keys which show nothing but when i insert a break point to see the data inside the ObservableCollection I can see that every thing from Users and Units table is there
private void MainContentsWindow_ContentRendered(object sender, EventArgs e)
{
using (var db2 = new DataContext())
{
var AllItems2 = new ObservableCollection<Model.Items.Item>(db2.Items);
ItemsDataGrid.ItemsSource = AllItems2;
}
}
Users
public class User
{
public User()
{
Id = Guid.NewGuid();
IsActive = false;
}
public Guid Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public UserGroup Group { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Items.Item> Items { get; set; } = new List<Items.Item>();
}
public enum UserGroup
{
Administrator = 1,
User,
Unknown
}
base
public class NormalBaseModel : CommonBase
{
public NormalBaseModel()
{
Id = new Guid();
CreateDate = DateTime.Now;
EditDate = null;
}
public Guid Id { get; set; }
public string Notes { get; set; }
public virtual User CreateBy { get; set; }
public DateTimeOffset? CreateDate { get; set; }
public virtual User EditBy { get; set; }
public DateTimeOffset? EditDate { get; set; }
}
items
public class Item : NormalBaseModel
{
public string NameAr { get; set; }
public string NameEn { get; set; }
public int? ManualId { get; set; }
public string Barcode { get; set; }
public byte?[] Image { get; set; }
public virtual Unit Unit { get; set; }
public string MadeIn { get; set; }
public bool IsSerail { get; set; }
public bool IsExpire{ get; set; }
}
Here is a test project on Github
https://github.com/ahmedpiosol/psychic-parakeet.git
https://imgur.com/a/zimd4
When you load your items via EF it needs to create new instances of User and Item. Behind the scenes, EF will call the constructor for each new instance. Your problem is in your constructors:
public User()
{
Id = Guid.NewGuid(); // <- here
}
Your constructor reassigns a new ID each time an instance is created, this will break the referential integrity and cause all sorts of other problems.
Your code doesn't know the difference between creating a new User and recreating a User instance from the database.
I suggest removing the assignments from inside your constructor and placing this either in a static Create method or place wherever you are creating a new User or Item.
p.s. WPF is irrelevant to your problem here.
Fluent API needs to specify foreign key in code, something like
modelBuilder.Entity<Items>()
.HasRequired(o => o.User)
.WithMany(c => c.Items)
.HasForeignKey(o => o.UserId);

Object doesn't add with children - EF Code First

It's been quite a while since I last used EF. I've never had any problems using it before. Now I'm attempting to insert an object that has a one-many relationship with another object. But in the API call, the collection array of the child object is shown to be empty however the parent object can be seen in the api call of the child object.
I have my models as below:
Conversation Table
public class Conversation
{
public Conversation()
{
this.ChatMessages = new List<ChatMessage>();
this.DeletedConversations = new List<ConversationDeleted>();
}
public int ConversationID { get; set; }
public string toUser { get; set; }
public string FromUser { get; set; }
[InverseProperty("Conversation")]
public ICollection<ChatMessage> ChatMessages { get; set; }
public ICollection<ConversationDeleted> DeletedConversations { get; set; }
public DateTime CreatedAt { get; set; }
public int UserID { get; set; }
}
ChatMessage Table
public class ChatMessage
{
public int ChatMessageID { get; set; }
public string fromUser { get; set; }
public string toUser { get; set; }
public string Message { get; set; }
public bool DeliveryStatus { get; set; }
public DateTime CreatedAt { get; set; }
public Guid UniqueID { get; set; }
public int ConversationID { get; set; }
[ForeignKey("ConversationID")]
public virtual Conversation Conversation { get; set; }
public ICollection<MessageDeleted> MessagesDeleted { get; set; }
public int UserId { get; set; }
}
My Fluent API looks like this:
modelBuilder.Entity<ChatMessage>()
.HasRequired(x => x.Conversation)
.WithMany(x => x.ChatMessages)
.HasForeignKey(x => x.ConversationID);
I'm trying to create a conversation entity and add a chat object to it's collection. I do it like so:
public IHttpActionResult CreateConversation()
{
ChatMessage msg = new ChatMessage { CreatedAt = DateTime.UtcNow, DeliveryStatus = true, fromUser = "annettehiggs", toUser = "terrydriscoll", Message = "Hum tum", UniqueID = Guid.NewGuid(), UserId = 43 };
Conversation conv = new Conversation();
conv.ChatMessages.Add(msg);
conv.CreatedAt = DateTime.UtcNow;
conv.FromUser = "annettehiggs";
conv.toUser = "terrydriscoll";
DataModel db = new DataModel();
db.Conversations.Add(conv);
db.SaveChanges();
return Ok(conv);
}
and this is how I retrieve the conversation object:
public IQueryable<Conversation> GetConversations()
{
return db.Conversations;
}
As a result, ChatMessage API call shows the conversation it's associated to but the Conversation object doesn't show the chat in it's collection. What am I doing wrong here?
The add code is working properly (otherwice you'll not be able to see the new chat message). The problem is with your data retrieval code.
Since your ChatMessage.Conversation property is marked as virtual, most probably it gets lazy loaded, that's why you see it populated.
At the same time, your Conversation.ChatMessages is not virtual, hence you need to explicitly eager load it using the Inlclude method, or depending on your requirements, mark it virtual to get the lazy load behavior like the inverse navigation property.

Entity Framework, eager loading entites

I have 3 classes which I would like to 'talk' to each other on a ASP.NET MVC C# WEBAPI app. They are, Item, which can have only one User but the User can make multiple Comments on multiple Items and a Comment can have multiple Users but only one Item
My classes are as follows:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Comment> Comments { get; set; }
public User User { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public ICollection<Item> Items { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Message { get; set; }
public bool Important { get; set; }
public Item Item { get; set; }
public User User { get; set; }
}
I'm using angularJs front end, and so that I don't get a forever repeating loop I have configured the following:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
I'm using entity framework 6 and I want to Display all items including the comments and the users who have commented
I have read and feel? that Projection using Linq is probably best?
I have the following in my dbContext. (P.S, I've disabled LazyLoading, and including the System.Data.Entity namespace)
using(var _db = new dbContext)
{
var model = _db.Items.Include(i=>i.Comments.Select(p=>p.User).Select(vm=>new ViewModelItem(){
//here I think is where I would say....
ViewModelItem.Name = x.Name,
ViewModelItem.Description = x.Description,
ViewModelItem.Comments = ///
ViewModelItem.Comments.User.Name = ///
})).ToList();
return Ok(model);
}
I'm not sure where to go from here.
So I want to display All the comments and include the User who owns the Item but also include All the comments for that Item, and all the Users who have commented on that Item.
Without causing an infinite loop.
If I'm not being clear, please ask me to clarify. Any help as always is greatly appreciated.
Thank you
Assuming your comments data is good this should do it.
var model = db.Comment.Select(p=>
new ViewModelItem {
Name = p.User.Name,
Comments=p,
Description=p.Item.Description,
});

Categories