Collection on model not updating to database - c#

I have a collection on a model:
[Table("Templates")]
public class Template
{
[Key]
public Guid ID { get; set; }
public virtual IList<TemplateSection> Sections { get; set; }
}
[Table("TemplateSections")]
public class TemplateSection
{
internal TemplateSection() { Fields = new List<TemplateField>(); }
[Key]
public Guid ID { get; set; }
[Required]
public Guid TemplateID { get; set; }
public virtual Template Template { get; set; }
}
This appears to create the correct relationships in the database.
When I update my database any sections I have added are not saved to the database. Here's how I'm updating the dabatase:
Template existingtemplate = db.Templates.Find(sltemplate.ID);
db.Entry(existingtemplate).CurrentValues.SetValues(template);
db.SaveChanges();
If I update inspect the existingtemplate before db.SaveChanges(); the Sections collection is null. Any other changes will have been updated onto existingtemplate.
If I add:
existingtemplate.Sections = template.Sections;
before db.SaveChanges(); then the sections will be saved to the database but aren't reloaded if I load the template again.
Obviously I have missed something in declaring the one-to-many relationship but having read dozens of articles I can't see what it might be.

The construct CurrentValues.SetValues only sets scalar properties, in other words, the non-navigation properties.
I'm a bit surprised that existingtemplate.Sections = template.Sections; apparently saves the TemplateSection objects, but doesn't establish the associations. I would have expected it to do neither or both.
One way to make sure that everything is saved correctly is to first load existingtemplate.Sections and Add() each TemplateSection object to it. This requires a database roundtrip though.
It's more efficient to attach the TemplateSection objects to the context and set their TemplateID property.

Related

Entity Framework ignore not included foreign keys

In my .net 6.0 project I use the Entity Framework 6 to get data from my database.
My model contains a foreign key, which is used to resolve the data of the id.
I use the following call to resolve the foreign key:
// ...
_context.Tools.Include(t => t.User).ToListAsync();
// ...
My Tool Model looks like this:
[Table("MY_TOOLS")]
public class Tool
{
[Key]
[Column("ID")]
public int Id { get; set; }
[Column("UPDATED_BY")]
public int? UpdatedBy { get; set; }
[ForeignKey("UpdatedBy")]
public User? User { get; set; }
}
My User class looks like this:
[Table("MY_USERS")]
public class User
{
[Key]
[Column("ID")]
public int Id { get; set; }
[Column("EMAIL")]
public string? Email { get; set; }
}
When I leave the include like described above, the user is resolved correctly.
Is there a way to remove the user property from the loaded data, when I don't explicitly tell the Model to resolve the foreign key?
It shouldnt resolve it by default as it uses lazy loading. You would have to query it specifically for the user object to get it e.g. _context.My_Tools.include(uvar = uvar.User).FirstOrDefault();
So you just make a method called getToolEager() and one called getTool()
it would be a "waste" of a call to query for the user object only to throw it away in case you might not need it.
You have 2 options:
Lazy Loading Proxy
Use Lazy Loading as described here:
https://learn.microsoft.com/en-us/ef/core/querying/related-data/lazy
After just load data as _context.Tools.ToListAsync(); and users will load when you try access them.
Manually load related data
Modify Tool to explicitly store User FK:
[Table("MY_TOOLS")]
public class Tool
{
[Key]
[Column("ID")]
public int Id { get; set; }
[Column("UPDATED_BY")]
public int? UpdatedBy { get; set; }
[ForeignKey("UpdatedBy")]
public User? User { get; set; }
public int? UpdatedBy{ get; set; }
}
So when you load data as _context.Tools.ToListAsync(); fieldUser will be null but UpdatedBy will have User Id(if FK is not null in DB), so you can manually load them manually like tool.User = await _context.Users.FirstOrDefaultAsync(t => t.Id == tool.UpdatedBy);

Model is not fully loaded out of DB after save from EF-Core

I have a EF-Core Code-First apporach. Im Saving a HolderModel into a Database which contains a ID and a List of Models.
On Saving everything works fine. The Struktur is correct and all data is in the Database. But if i load the data back into my code, the List of Models is gone.
Im a bit confused as usally EF did everything by him self.
Am i missing something for EF-Core ?
Here is the codesnippet:
DB-Context:
public DbSet<FinancialStateHolderModel> States { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlServer(
#"Server=.\;Database=Stock;User Id=dbuser;Password=dbuser");
builder.EnableSensitiveDataLogging(true);
}
HolderModel:
public class FinancialStateHolderModel
{
[Key]
public String Symbol { get; set; }
public List<FinancialStatementModel> Financials { get; set; }
}
Models:
public class FinancialStatementModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime Date { get; set; }
}
Please check Loading Related Data in Entity Framework.
You're looking for
Eager loading - the related data is loaded from the database as part
of the initial query
In your case(example not exact syntax because I don't know what your call looks like)
should be context.FinancialStateHolders.Include(x=> x.FinancialStatements)

Invalid Column exception

Hi guys I am getting this exception when I try to run the vehicles page.
Invalid column name 'MakeID'.
I have two models:
public class Vehicle
{
public int VehicleID { get; set; }
public string Title { get; set; }
[ForeignKey("Make")]
public int MakeID { get; set; }
public virtual Make Make { get; set; }
}
public class Make
{
public int MakeID { get; set; }
public string Title { get; set; }
}
The error is being thrown in my vehicles controller here
public ActionResult Index()
{
var vehicles = db.Vehicles.Include(v => v.Make);
return View(vehicles.ToList());
}
Add/Enable Migrations. Update the Database. Most of the case improper update causes the issue. There is no problem with your above code.
Make sure: you have Updated the Database Tables after adding new columns.
Run the Update-Database command in Package Manager Console.
Make sure your column Foreign Key Relationship / Mappings are ok.
You have to check it out manually.
There are four ways to Drop and Create the Database. Based on several conditions. OR you can manually delete the Database from SQL Server.
Good Article and Source can be found here - Programatically.
Note: Recreating the Database will lose the entire existing data. There is one way to avoid this problem. It's providing Seed Data to the database / Tables on create.

How to avoid Lazy Loading when accessing foreign key ID property through navigation property?

I'm in the process of converting a project from NHibernate to Entity Framework 6.
Given this simple model:
public class User
{
public int ID { get; set; }
public string FullName { get; set; }
public virtual Organization Organization { get; set; }
// [...]
}
public class Organization
{
public int ID { get; set; }
public string Name { get; set; }
public virtual List<User> Users { get; set; }
// [...]
}
Accessing the primary key (ID) through the Organization navigation property will cause the whole Organization entity to be loaded into the context:
foreach(var user in db.Users)
Console.WriteLine(user.Organization.ID);
Given that the OrganizationID foreign key is part of the User row, I should be able to access it without causing a Lazy Load of the whole entity (and indeed, NHibernate does this properly).
Short of adding properties for the foreign key IDs into all of my 100+ entities so I can access their values without loading the entities, is there anything to be done to avoid this behaviour?
EDIT: Furthermore, even doing a null check will cause a load of the Organization entity (not in NHibernate):
foreach(var user in db.Users)
Console.WriteLine(user.Organization != null);
I guess this is due to the fundamental differences in the way the entity proxy is implemented in these two frameworks. So I'll have to adapt all of my code to this new frustrating behaviour... Unless someone already had to go through this and could enlighten me?
Nope, you'll need to add them as property in your class (that is; if you want it strong typed) like this to access it directly.
public class User
{
public int ID { get; set; }
public string FullName { get; set; }
//added ID
public int OrganizationID { get; set; }
public virtual Organization Organization { get; set; }
// [...]
}
By accessing the int you'll prevent the lazy loading, EF will bind the ID through naming conventions. Having said that: 100+ classes... :|
UPDATE:
As I just realized; you might want to try:
db.Users
.Include("Organization.ID")
.Where(/*your stuff*/) //etc.;
I am not certain if it will fully load the nested property. If it doesn't, it might be a small performance gain.

Save a Child for a existent Parent

I have a model with some inherits and it is using nhibernate to persisti on a Database. The nhibernate mapping with fluent nhibernate is working fine, but I have a scenario where I need to save a child for a existent parent. My model looks like this:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
// other properties
}
public class ItemCommercial : Item
{
public decimal Value { get; set; }
// other properties
}
In my Database, the respective tables are related by Id <-> Id (one per one).
I would like to know, how to Save just a ItemCommercial instance for a existent Item on database. I have the Id of the Item, but I do not know howt to say to nhibernate to say just the Child, instead creating a new Item, for sample:
session.Save(itemCommercialObj); // will create a Item and ItemCommercial with the same Id
Thank you.
As I also answered here
No, it is not possible to "upgrade" an already persisted object to its subclass. Nhibernate simply doesn't support this.
If you safe the subclass with the same ID as the base class, Nhibernate simply creates a copy with a new ID of the object instead of creating the reference to Member...
So basically you could do either
Copy the data of Customer into Member, delete customer and save Member
Use a different object structure without subclasses where Member is a different table with it's own ID and a reference to Customer
Use native sql to insert the row into Member...
you can not the runtimetype of an object like that hence NH does not support it. Change the design to
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public CommercialValue CommercialValue { get; set; }
// other properties
}
public class CommercialValue
{
public Item Item { get; set; }
public decimal Value { get; set; }
// other properties
}
and a one-to-one mapping. Then it is as simple as setting the CommercialValue property

Categories