Breeze navigation properties not loaded - c#

I have the following many to many model between Project and UserProfile entities. As many to many relationships is not supported in Breeze yet, I am exposing the middle entity ProjectMember as well. So the server side code looks like the following:
public class Project
{
public int ProjectId { get; set; }
public String Name { get; set; }
public virtual List<ProjectMember> ProjectMembers { get; set; }
}
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public virtual List<ProjectMember> ProjectMembers { get; set; }
}
public class ProjectMember
{
public int ProjectId { get; set; }
[ForeignKey("ProjectId")]
public Project Project { get; set; }
public int UserId { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}
The metadata returned from the server seems to be the right one:
The navigation property seem to be properly sent out by the server.
When I request a project from the client by doing:
var query = entityQuery.from("Projects")
.where('projectId', '==', projectId)
.expand("projectMembers");
The returned JSon data is the one expected:
However, the Project.ProjectMembers navigation property is not properly constructed on the client side as you see from the screenshot below:
I went through the tutorials, the breeze documentation, the SO questions related to navigation properties and I still don't see what I am doing wrong.
Question:
Given the information above, why is Breeze not loading the ProjectMembers navigation property?

I would start by checking the EntityManager's metadataStore to make sure that the ProjectMember entityType can be found. You can do this after your first query via
var projectMemberType = myEntityManager.metadataStore.getEntityType("ProjectMember");
If the projectMemberType is not found then the problem has to do with the metadata not being brought down correctly.
Another possibility, have you defined a key for the ProjectMember type ( presumably a two part key)?

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);

Foreign key may cause cycles or multiple cascade paths

I am trying to create a (in my opinion) quite simple setup, but I can't figure out why I keep getting this error when I run Update-Database:
Introducing FOREIGN KEY constraint 'FK_dbo.Breweries_dbo.Pages_PageId' on table 'Breweries' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I am trying to setup this structure:
Brewery > Page > IdentityUser
This is my classes:
public class Brewery
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Guid BreweryId { get; set; }
[Required]
public string Name { get; set; }
[Required]
[ForeignKey("Page")]
public Guid PageId { get; set; }
public virtual Page Page { get; set; }
public virtual ICollection<Image> Images { get; set; }
}
public class Page
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Guid PageId { get; set;}
[Required]
public string Title { get; set; }
public string Content { get; set; }
[Required]
[ForeignKey("CreatorUser")]
public string CreatorUserId { get; set; }
public virtual IdentityUser CreatorUser { get; set; }
}
I have seen a lot of other Stack Overflow posts and it seems like I should be setting something up in the OnModelCreating, but I can't get it right. I would like to avoid having a ICollection<Brewery> Breweries property on the Page, since I want many different entities to reference to the Page entity and it is irrelevant for a Page who is referencing to it.
I am new to Entity Framework and Code First so I might have approached this wrong without knowing. I would appreciate any help to setup the relationships correct.
As the association between Page and Brewery is required, EF defaults to cascaded delete. But if there are many entities referring to Page there will be multiple cascade paths and you have to override the default:
modelBuilder.Entity<Brewery>()
.HasRequired(b => b.Page)
.WithMany() // <= no inverse collection in Page.
.HasForeignKey(b => b.PageId)
.WillCascadeOnDelete(false);
You can only do this by fluent mapping. Also, this replaces the attributes on Brewery.PageId.

double relationship between entities in EntityFramework 6

My problem looks simple. I need to implement a relationships between items in the database. For example: relationship between entities like computer and software shows users that computer stores a specific software and similarly - a software is installed in the specific computer. I think I should implement an entity with source id and target id or something similar. I wrote some code using code first in EntityFramework 6. Here are two classes:
public class ConfigurationItem
{
public int Id { get; set; }
public String Name { get; set; }
public String DeploymentState { get; set; }
public String IncidentState { get; set; }
[DataType(DataType.MultilineText)]
public String Description { get; set; }
[DataType(DataType.MultilineText)]
public String Note { get; set; }
public virtual ICollection<Relationship> Relationship { get; set; }
}
public class Relationship
{
[Key]
public int RelationshipId { get; set; }
[ForeignKey("ConfigurationItem")]
public int SourceId { get; set; }
[ForeignKey("ConfigurationItem")]
public int TargetId { get; set; }
public String Type { get; set; }
public virtual ConfigurationItem Source { get; set; }
public virtual ConfigurationItem Target { get; set; }
}
This solution doesn't work. I need a tip or something what should I try to make it work properly. EF throws an error about foreign key:
The ForeignKeyAttribute on property 'SourceId' on type 'cms_1.Models.Relationship' is not valid. The navigation property 'ConfigurationItem' was not found on the dependent type 'cms_1.Models.Relationship'. The Name value should be a valid navigation property name.
When I try to resolve it EF throws an error about cascade deleting. I know how to disable it but I just don't want to. I need a proper solution with that feature but I think I don't know how to do a model representing given scenario.
Simply - I need to store two foreign keys from entity "A" in the entity "B". How is it possible?
from a quick review , I can tell that you need 3 tables :
first : Computer
second : Software
third : a table , lets call it ComputerSoftware which tell which software has in what computer ( or you can also see it - which computer use what software ), which has ComputerID column and SoftwareID column.
example (source)
class Country
{
public int Id { get; set; }
public virtual ICollection<CountryCurrency> CountryCurrencies { get; set; }
}
class Currency
{
public int Id { get; set; }
}
class CountryCurrency
{
[Key, Column(Order=0)]
public virtual int CountryId { get; set; }
[Key, Column(Order=1)]
public virtual int CurrencyId { get; set; }
public virtual Country Country { get; set; }
public virtual Currency Currency { get; set; }
}
Your issue could be that in the migration file creating those tables, it will have something like
.ForeignKey("dbo.Relationship", t => t.Id, cascadeDelete: true)
This will be set on both tables, ConfigurationItem and Relationship of their Primary Key fields. When you delete one, that config tells SQL Server to delete the relationships as well and the relationship probably has a cascadeDelete: true to the parent. This will cause the cyclical cascading delete issue you are experiencing.
After the migration has been generated, go in and change one or all to cascadeDelete: false and this will fix that issue. This is what EF generates by default if I recall.

How do I use EF6 with Database First and existing views?

I'm an EF noob (any version) and my Google-foo has failed me on finding out how to do this. Which makes me think I must be doing this wrong, but here is the situation:
I'm definitely in an environment that is database first and the schema won't be updated by us coders. I'm also not a fan of 'automatic' code generation, so I've stayed away from the designer or the EF powertools (though I did run through them just to see them work).
To learn I imported the Northwind DB into my LocalDB to have something to play with while creating some simple Web API 2 endpoints. This all went well as I created slimmed down models of the Employees, Shippers, & Region tables in Northwind. Region was particularly interesting as it wasn't plural and EF had issues with that. Anyway, I got by that.
My trouble now is; I want to use a view instead of a table as my source and whatever I'm doing just doesn't seem to work. What I tried was setting it up just like I did the tables. But that produces a ModelValidationException error. I tried looking at the auto-generated code from the designer, but got no insight.
My models:
//-- employee, shipper, & region work as expected
public class employee {
public int EmployeeID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
public class shipper {
public int ShipperID { get; set; }
public string CompanyName { get; set; }
public string Phone { get; set; }
}
public class region {
public int RegionID { get; set; }
public string RegionDescription { get; set; }
}
//-- invoice is a view (actual viewname is 'Invoices')
//-- so i followed the same rules as i did for employee & shipper
//-- i have tried uppercase 'I' as well as a plural version of the model
public class invoice {
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public string Salesperson { get; set; }
public int OrderID { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
}
My Context looks like this:
public class NorthwindDBContext : DbContext {
public DbSet<Employee> Employees { get; set; }
public DbSet<shipper> Shippers { get; set; }
public DbSet<region> Regions { get; set; }
public DbSet<Invoice> Invoices { get; set; } //-- offending line of code
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
//--- fix for Region being singular instead of plural
modelBuilder.Entity<region>().ToTable("Region");
}
}
If I comment out the public DbSet<Invoice> Invoices { get; set; } line in the context everything works. Just by having the line present (even if i don't reference the Invoices property) I receive the ModelValidationException error when using the context in anyway.
Can anybody tell me what I'm doing wrong here?
Thanks.
Update: I tried this in one of my controllers, but I am too noob'ish to know if this is the right path either, though it worked as far as getting records.
using (var dbContext = new NorthwindDBContext()) {
return dbContext.Database.SqlQuery<Invoice>("select * from invoices").ToList();
}
Code-first conventions will look for an ID or InvoiceID property to use as a key. Your Invoice model has neither, while the others do. This is the specific reason your code is failing.
The less-specific one is that you can't have entities in EF which lack a unique key. If you can, have the view define a key. Otherwise, you may still be able to work around the issue.

How to prevent Fluent NHibernate from adding "Parent" table's FK to relationship tables?

I have the entities:
public class Plugin
{
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual Plugin ParentPlugin { get; set; }
public virtual IEnumerable<Setting> Settings { get; set; }
}
public class Setting
{
public virtual int Id { get; set; }
public virtual Plugin Plugin { get; set; }
public virtual int Version { get; set; }
}
The problems is that when I added ParentPlugin, it added a ParentPlugin_Id to the Setting table in the DB. I can't figure out why it did this, however I'd like for Setting to only have a Plugin_Id not both Plugin_Id and ParentPlugin_Id in the database.
So, I would like to know 2 things to receive bounty:
1. How can I remove the ParentPlugin_Id reference from Setting?
2. And why did it do this in the first place (link to doc is ok, I could not find one explaining this)?
I'm using Fluent Nhibernate's automapping, mostly all defaults.
By specifying the exact FK name I was able to remove the extra ParentPlugin_Id. A bit counter intuitive to have to add an FK instead of removing one but...
.Override<Plugin>(m => m.HasMany(c => c.Settings).KeyColumn("Plugin_Id"))
This was figured out by a deeper understanding of the Foreign Key Conventions (https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping)

Categories