I have a structure of 'Folder' entities. Each Folder has a reference to its parent Folder, allowing for a standard tree structure. Each folder can also have a collection of items, let's call them 'Articles'. An article has a title and a body. Given the ID of a root folder, I want to retrieve all the subfolders and their articles. However, I want to only retrieve the article title, not its body. I intend to display the folder structure in a tree view, and I want to retrieve the full article only if the user selects the article in the tree view.
I have set up the relations like so:
public class Folder: EntityBase
{
public string Name { get; set; }
public Guid ParentId { get; set; }
[ForeignKey(nameof(ParentId))]
public Folder Parent { get; set; }
public ICollection<Folder> Folders { get; set; }
public ICollection<Article> Articles { get; set; }
}
public class Article : EntityBase
{
public Guid FolderId { get; set; }
[ForeignKey(nameof(FolderId))]
public Folder Folder { get; set; }
// this needs to appear in the list
public string Title { get; set; }
// potentially large amount of data, retrieve only as necessary
public string Body { get; set; }
...
}
What I can't figure out is how to tell Entity Framework to recursively go through all the subfolders and their subfolders and so on. Do I have to implement recursion in my code? That seems a bit inefficient. Is there a preferred way to handle this?
Also, how do I retrieve just the title field of my articles, not the whole body?
Do I have to implement recursion in my code
The alternative recursively loading from the client is load all the Folders with a single query, and let EF fix-up the relationships. If you don't want to load all the Folders, you can perhaps use a SQL query to just the Folders under a particular Folder (eg using a recursive CTE).
how do I retrieve just the title field of my articles, not the whole body
EF doesn't support partially loading a single Entity, but you can use "Table Splitting" to split ArticleBody into a separate Entity, even if it is on the same table.
Related
EF7 fills contained navigation properties even when not requested. For example, I have the below entities.
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
My fetch query is as below.
ctx.Employees.Where(e => e.Gender == "Male").Include(e => e.Department)
I get Department property of Employee object filled – which is as expected as I have an Include for Department. I find that Department.Employees is also filled but partially (only with male employees). I have not specified an Include for Department.Employees, but it is still getting populated. Is this behavior by design? Is there any way to avoid fetching Department.Employees in this scenario?
I am using EF7 NuGet package with version 7.0.0-rc1-final.
That is the normal behavior of EF. When you execute your query, all the entities you load is going to be attached to your context. So, EF is not executing another query and loading Department.Employees partially, those employees were loaded earlier when you execute your query. In summary, when you consult Department.Employees navigation property, EF is going to fill that property with the employees that you load with your query filtering by Gender.
Update:
As I pointed out in my comment above, Lazy Loading is not supported in EF7. If you want to avoid that Json.NET serializes that property, you can use the attribute JsonIgnore over that property or you can create a custom class (DTO) to project your query and fill only the properties that you need. I also recommend take a look to Automapper if you decide to use this last solution.
In Entity Framework when I want to specify that an entity has many of another type of entity it seems to do things backwards to me.
For instance let's say I have a keyword entity that is used in several places throughout my app. All keywords are unique but on my other entities I want to have multiple keywords attached them so to me this would make sense:
class Page
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Keyword> Keywords { get; set; }
}
class Search
{
public int ID { get; set; }
public DateTime Date { get; set; }
public virtual ICollection<Keyword> Keywords { get; set; }
}
class Keyword
{
public int ID { get; set; }
public string Name { get; set; }
}
However when I do this the foreign key is added to the Keyword table whereas I want it to be on the actual entity so I can look at it in database and see small list of keywords instead of looking at keyword and seeing a ridiculous large number of page results.
So instead to get Entity Framework to put the Keyword_IDs on Page and Search entities I am doing this:
class Page
{
public int ID { get; set; }
public string Name { get; set; }
}
class Search
{
public int ID { get; set; }
public DateTime Date { get; set; }
}
class Keyword
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Page> Pages { get; set; }
public virtual ICollection<Search> Searches { get; set; }
}
This feels backwards as I am specifying the relationship on the entity that doesn't get the foreign ID field in the database table.
I feel like I am doing something wrong as I should be able to see the relationship by looking at my search & page class.
I am sorry for the basic question but for some reason I have read documentation and I am not fully understanding it.
In a one-to-many association it's always the many side that refers to the one side. How else would you implement it? If a Page would have a KeywordId as FK, it could only have one keyword, ever.
Also, even when a Keyword would belong to a myriad of pages, that doesn't mean you always have to access all of these pages through one keyword. You'd only do that if you'd do a search for pages in which specific keywords are used.
But now back to your model. You can't have one-to-many associations here. It would mean that any keyword can only belong to one Page or one Search. And if you invert the relationship, as you proposed, a Page or Search can only ever have one keyword (the one that Keyword_ID refers to).
In reality, you're dealing with many-to-many associations and the good news is, it leaves your Keyword intact.
Modelling it as many-to-many doesn't change the way your model looks (the first version), but the mapping is different:
modelBuilder.Entity<Page>().HasMany(p => p.Keywords)
.WithMany()
.Map(m =>
{
m.ToTable("PageKeyword");
m.MapLeftKey("PageID");
m.MapRightKey("KeywordID");
});
modelBuilder.Entity<Search>().HasMany(s => s.Keywords)
.WithMany()
.Map(m =>
{
m.ToTable("SearchKeyword");
m.MapLeftKey("SearchID");
m.MapRightKey("KeywordID");
});
This will generate two junction tables in your database, PageKeyword and SearchKeyword that record the many-to-many associations.
In an MVC4 web application using the Razor engine and entity framework, is it possible to create a template for use with the html helper #Html.EditorForModel , so that entities with links to other tables are better displayed.
The example I am working with is a DbContext containing two DBSets, Regions and Schools. There are many regions, and a school may belong to one region. Ideally I would like the editor for schools to show a dropdown of regions to select from. I would like to make a template that is generic enough so that I can just call the #Html.EditorForModel helper and the form is generated in one go, and that I could make changes to the region or schools tables later on and for the changes to be reflected in the edit form without me needing to make alterations.
Some code:
public class MyContext : DbContext
{
public MyContext ()
: base("DefaultConnection")
{
}
public DbSet<Region> Regions { get; set; }
public DbSet<School> Schools { get; set; }
[Table("Regions")]
public class Region
{
public Region()
{
Schools = new List<School>();
}
[Key]
public int RegionId { get; set; }
[StringLength(256)]
public string RegionName { get; set; }
public ICollection<School> Schools { get; set; }
}
[Table("Schools")]
public class School
{
public School() { }
[Key]
public int SchoolId { get; set; }
[StringLength(256)]
public string SchoolName { get; set; }
[ForeignKey("Region")]
public int RegionId { get; set; }
public virtual Region Region { get; set; }
}
}
I have created a partial view to create display the editor form, with the idea that I can pass in either a Region or a School as the view model.
#model object
#using (Html.BeginForm())
{
#Html.ValidationSummary("Broken stuff:")
#Html.EditorForModel()
}
I don't know if this is possible, but I would really like the new template to loop over the properties of the entity and detect if there is a linked table (e.g. School contains a Region) and display the list of regions in a dropdown.
Well, in general, it's a bad idea to pass your data models directly to your views for rendering. There are security issues there, among other things. But, even if you are going to do this you would not want to pass your entire data context like that because it's not structured in a way that is suitable for rendering in a web page.
Off corse you can. Look at here to see how.
An alternation is that you use scaffolding and let it to create your views. Most of times(!) it creates correct DropDowns for you and you just customize your view if you want.
And in those few situations that yo see strange DDLs, you just need to correct ValueName and DataName parameters in the related action methods whic return list items to the view...
I would like to create a nested set model inside my database. However, I have a problem, 'cause I don't know how to start the implementation using Entity Framework Code-First.
Lets say I have such class:
public class Category
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Category> SubCategories { get; set; }
// public int left { get; set; }
// public int right { get; set; }
}
In my model I need SubCategories collection as it is right now. However I would like to implement automatic (implicit) update of left and right properties when I add/remove subcategories to/from SubCategories collection.
Is it possible?
Thank you for any answer in advance!
Best!
Nested sets and object graphs are two totally different models. You shouldn't store both of them in one type; that violates SRP.
Instead, put Left and Right on your code-first POCOs, load the, and then project/copy that onto objects of a different type (which are not entities) with a graph schema.
I have problem I cannot find a solution for: basically I would like how to turn off cascading update on a EF CodeFirst many to many association.
I have two classes List and Recipient.
public class List
{
public string DisplayName { get; set; }
public DateTime? LastSyncronized { get; set; }
public virtual ICollection<Recipient> Recipients { get; set; }
}
public class Recipient
{
public int Id { get; set; }
public String Name { get; set; }
public virtual ICollection<List> Subscriptions { get; set; }
}
During some processing I need to add to the Recipients property of a List a number of Recipient that I take from an external source.
Then I do my processing and at the end I have to same the List to update the LastSyncronized property.
Unfortunately, when I save, the automatic tracking of EF also saves into the database all the Recipients I've taken from the external source.
How can I configure the DbContext not to persist the new objects to the Database?
I tried removing them all from the collection, but even that they are added to the database anyway. In this case, the join table is unchanged, but the recipient one is added with the new recipients.
Thank you
Simone
Not sure this is the right solution to this, but I set, in the DbContext class:
Configuration.AutoDetectChangesEnabled = false;
Now object added are not added to the database.