ASP MVC 5 - Remove Child Entities From Parent - c#

How can I remove All child entities from a one to many relationship via the parent - Note I only want to remove the children.
public class Parent
{
public int Id { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public virtual Parent Parent { get; set; }
}
Is there a shorthand way, lets say something like below:
parent.children.Remove();

I believe that your mechanism for deleting the child elements in EF 4 and above should be:
parent.children.ToList().ForEach(c => context.Children.Remove(c));
context.SaveChanges();
I have found in the past that it may be faster to write a DELETE yourself, but you should decide what is best for you. Introducing a SQL DELETE in an Entity Framework solution adds some complexity both to testing and because your DELETE will depend on things you may have been trying to avoid as EF takes care of it all. Always measure before you optimize and decide what trade-offs work for you.

Related

Retrieve from DB and Include Multiple ICollections

I'm working with EF6. I have a module with multiple ICollections. My solution to retrieve the lists of objects is similar but I find it dumb, as I need to rewrite this on all the pages where I need IEnumerable<BookModel> GetAllBook.
IEnumerable<BookModel> GetAllBook = DBContext.BookModels.Include(x => x.AssociatedNames).Include(e => e.BlogModel);
I read several topics on this but these stood out. From what I understood, the answer is written in the DbContext.cs with the DbSets. But does the BookModule have a complete list of example authors? Without the need of including another time?
Include several references
I also read
Why does EF Core One-to-Many relationship collection return null?
public class BookModel
{
[Key]
public int BookModelID{ get; set; }
public virtual ICollection<AssociatedNames>? AssociatedNames { get; set; }
public virtual List<BookModel>? relatedSeries { get; set; }
public virtual List<BookModel>? RecommendedBookModels { get; set; }
public virtual ICollection<AuthorModel>? Authormodels { get; set; }
public virtual ICollection<ArtistModel>? ArtistModels { get; set; }
public virtual ICollection<VoiceActorModel>? VoiceActors { get; set; }
public virtual ICollection<GenresModel>? GenresModels { get; set; }
public virtual ICollection<TagModel>? TagsModels { get; set; }
}
My question is there a way for my bookModel have the complete lists of objects without needing to use Include again, and again.
Best regards
What you need in this cas is the AutoInclude feature introduced with EF6 , so You will have to go into the OnModelCreating Method and add the following lines ( you update that to your use case , depends on which related entities you want to be autoIncluded ):
modelBuilder.Entity<BookModel>().Navigation(e => e.Authormodels).AutoInclude();
modelBuilder.Entity<BookModel>().Navigation(e => e.Artistmodels).AutoInclude();
and if , for a specific cas you need only the books , and you want to get rid of the autoIncludes , then us can use the IgnoreAutoIncludes feature like below :
var books = context.BookModels.IgnoreAutoIncludes().ToList();
Fore more details about this you can look up this documentation or this video

Get all children of same object by Entity Framework

I need your help. I have next simple class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public IEnumerable<Person> People { get; set; }
}
I need to get class by ID and all children of the class that have ParentId same with ID of first class (and children of children)? I need to use LINQ filtration. Thanks for help!
Okay, there are two solutions that I could find. The first is using the recursive method on the server-side. But in this variant, you need each time request database for each level of hierarchy. The best solution is using Recursion in SQL. You need to do only one request to the database. I attach the link. https://medium.com/swlh/recursion-in-sql-explained-graphically-679f6a0f143b

Correct way of mapping a 'one to many' relationship. When having the same relation in multiple entities

Suppose the following structure of classes and relationships:
class Document
{
public List<Version> DocumentVersions { get; set; }
// Other properties
}
class Register
{
public List<Version> RegisterVersions { get; set; }
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}
When using EF Core, it is going to produce 3 tables, D, R and V respectively where V is going to have 2 FK, one for D and one for R.
My questions are:
Is EF Core default approach correct? Wouldn't it lead to invalid states where V has no FKs because both FKs can be nullable.
I've read this and it almost answered my first question but it leads me to another question:
How can I tell EF to follow that approach: Should I have to create a derived type of V for each of its owners? or is there any way I can map a single entity to multiple tables and tell EF which relationships belong to which table?
Maybe is worth mention that my example is oversimplified and in reality I have 6 entities using the same V entity.
So, the dilemma is:
A) Should I keep two FKs in Version or
B) build two tables DocumentVersion and RegisterVersion instead of just Version?
Well, the truth is you can do both. You just have to decide which approach suits your system better. Let's have a quick look.
Approach A
To answer your question; yes EF's default approach is correct. Among creating two FKs and building two tables, it will create two FKs. It will create an extra table only in case of intermediate table for a many to many relashionship.
I always, though, recommend that we create all FKs ourselves instead of letting EF do it for us. This way we have more control over the behavior of the relationship and can also access the FKs in our application, since they are an entity's property.
public class Version
{
[Key]
public int VersionNumber { get; set; }
public int? DocumentID { get; set; }
public virtual Document Document { get; set; }
public int? RegisterID { get; set; }
public virtual Register Register { get; set; }
//Other properties
}
Since Version has a PK, it can create records without any of the FKs having any value. If this is allowed in your business model then leave it as it is. You can later provide a UI to assign "Versions" to either "Documents" or "Registers".
If you want to add some rules in your Version table; for example each record should have at least one FK or only one FK, you can do that by overriding the ValidateEntity method of your DbContext class (or through some sql constraint in the database probably).
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry, IDictionary<object, object> items)
{
// validate entity from annotations
var result = base.ValidateEntity(entityEntry, items);
// custom validation rules
if (entityEntry.Entity is Version &&
(entityEntry.State == EntityState.Added || entityEntry.State == EntityState.Modified))
{
Version version = ((Version)entityEntry.Entity);
if (version.DocumentID == null && version.RegisterID == null)
result.ValidationErrors.Add(new DbValidationError(null, "A document or register must be specified."));
}
return result;
}
Note that you can create your own annotations to validate your entity properties. But these are restricted to a single property. If you want to add validations that combine more than one property, the ValidateEntity method is the only way I know of.
Approach B
There are two ways to implement this approach. The first is to keep the Version table and add two intermediate tables on top.
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
public class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
public class RegisterVersion
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
This actualy allows a many-to-many relationship, but you can use it as a one-to-many.
The second way is to make Version abstract (not a database table) and build two new tables to inherit from Version:
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
// don't make this a DbSet
public abstract class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion : Version
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
// other properties
}
public class RegisterVersion : Version
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }}
// other properties
}
This is a proper and clear one-to-many relationship.
Conclusion
The bottom line is that you can use any of the two approaches and with alterations that suit your needs.
I have used both approaches successfully, but I tend to prefer the second one (and with the abstract class inheritance). The first approach seems more of a way to cut down on database resources or ease of development, but modern databases are not at all stressed by a few tables more and the development could become unnecessarily complex. Further more the second approach allows to extend the functionality of the relationships by adding further properties to each connection table seperatelly. And for the 6 entities you have to deal with, it seems safer to me to go with the second approach. I have used this approach in an application with many file types and relationships and it was always very straight-forward and extendable. Those extra properties in each relashion table came very handy too.
Hope I could help,
merry coding!
I don't think this really is a one-to-many relationship, look here.
It would be a one-to-many relationship if (for example) Document had multiple (e.g. a list of) Versions.
If you want multiple entities refering to the same entity type, you could place the foreign keys explicitly in the Document and Register classes:
class Document
{
public Version DocumentVersion { get; set; }
public int DocumentVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Register
{
public Version RegisterVersion { get; set; }
public int RegisterVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}

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)

Retrieving Hierarchal data in Entity Code-First

I have some hierarchal data. The Model class I use looks like this:
public class Category
{
[Key]
public int CategoryID { get; set; }
[Required]
[StringLength(64)]
public string Name { get; set; }
public int? ParentCategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public Category ParentCategory { get; set; }
[Required]
public int ListOrder { get; set; }
// left/right
public int TreeLeft { get; set; }
public int TreeRight { get; set; }
} // eo class Category
I've used the techniques outlined here to store my data, and inserting and retrieving data is not a problem.
What I would like to do, is add a Category collection to this class:
public virtual IEnumerable<Category> {get; set; }
I've used this technique in the past (learned from the Mvc tutorials), to include related tables when getting data. However, when I tried this I received an error with regard to IEnumerable<> being abstract (which is understandable, I guess the framework couldn't figure out what I want to do)...
... and indeed, being new to LINQ, I have no idea what the LINQ would look like that would give me back a collection of Category instances each of which had their children inside them.
If it's not possible I guess I can construct the list manually, use a regular LINQ query to get all the categories at a particular position (and their children) and manually populate it all.
I was wondering if LINQ could do this for me?
Thanks in advance!
If you have a self reference fk than the collection should be generated automatically when you add the table to the dbml file
And will look something like this:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Category_Category", Storage="Categories", ThisKey="pkCategoryID", OtherKey="ParentCategoryID")]
public EntitySet<Category> Categories
{
get
{
return this._Categories;
}
set
{
this._Categories.Assign(value);
}
}
Dont use IEnumerable<Category> but Collection<Category> . If that is your problem..

Categories