Soft delete on many to many relationships [duplicate] - c#

This question already has answers here:
Create code first, many to many, with additional fields in association table
(7 answers)
Closed 4 years ago.
The only question that I found most similar to my question is here, But It didn't answer my question. I have this model:
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted {get; set; }
public virtual ICollection<Program> AllowedPrograms { get; set; }
public virtual ICollection<Program> DisAllowedPrograms { get; set; }
}
and this :
public class Program
{
public int Id { get; set; }
public string DisplayName { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted {get; set; }
public virtual ICollection<Profile> AllowedProfiles { get; set; }
public virtual ICollection<Profile> DisAllowedProfiles { get; set; }
}
If I implement soft delete by help of IsDeleted field, What happens to entries in ProfileProgram table ? Are they deleted too implicitly? (There is two many-to-many relationships in this model I guess ). If I use entity framework filters which is located in here.
Or should I create the intermediate table by myself and add IsDeleted field to that? Also this approach seems to change my code a lot which I am really looking for alternate method.

Yes the ProfileProgram table isn't automatically deleted. Yes you should create the IsDeleted table (not field).

Related

EF Core 6 One to Many Populate Many List

I am learning EF Core and having some trouble understanding the One to Many Setup, particularly the Many part. I have googled and searched stack overflow but can't seem to find an obvious answer to my question.
I am using SQL Server community and a Code First approach. I have the following two entities, and can I insert a Person record into the database with the Foreign Key without issue. My question is when/where/how does the Persons List in Nationality get populated, as it doesn't seem to do it automatically. Is this something I can set up in EF, or do I need to populate it manually?
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public int? NationalityId { get; set; }
public virtual Nationality Nationality { get; set; }
}
public class Nationality
{
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Person> Persons { get; set; }
}

eventlog shows invalid column name although I don't have that in my model

I have the following database model class called positions:
public class Positions
{
public string? Id { get; set; }
public string? ArticlePLU { get; set; }
public string? ArticleName { get; set; }
public string? ArticleGroupPlu { get; set; }
public string? ArticleGroupName { get; set; }
public string? MenuId { get; set; }
public string? MenuName { get; set; }
public string? MenuLineId { get; set; }
public string? MenuLineName { get; set; }
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public List<Vat>? Vat { get; set; }
public List<AdditionalCost>? AdditionalCost { get; set; }
public List<Components>? Components { get; set; }
public Comment Comment { get; set; }
[ForeignKey("Orders")]
public string? OrdersId { get; set; }
}
I also have the following class called Comment:
public class Comment
{
public string? Id { get; set;}
public string? Type { get; set;}
public string? Value { get; set;}
[ForeignKey("Components")]
public string? ComponentsId;
[ForeignKey("Positions")]
public string? PositionsId;
}
The class comment is a child of positions but it can also be a child of components, which itself is a child of positions, but I don't think thats relevant to the problem right now.
The eventlog of IIS shows that whenever I try to send data with Postman it cannot recognize a column called "CommentId" which does not exist in any classes and isnt referenced anywhere. My guess is that EntityFramework, which im using, is doing something in the background because I have not configured everything correctly. The 'Comment' data is supposed to be in another table. When the data is received, the Comment should get an own unique Id through my controller class and EF handles the foreign key.
Since the Comment is the non nullable Child of the Position, Entity Framework automatically add Foreign KeyCommentId
column to the table Positions. In order to solve this, you can make the Comment to be Nullable by adding ? in the Comment Property in Position model
public Comment? Comment { get; set; }
This will remove EF Core from automatically add new column CommandId to table Positions
Edit :
Configure using Fluent Api the relationship between Comment and Position..
modelBuilder.Entity<Position>()
.HasOne(p => p.Comment)
.WithOne()
.HasForeignKey<Comment>(p => p.PositionsId);
Just put this inside your DbContext class. Learn more here : https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

EF Core 2.2.6: Unable to map 2 foreign keys to the same table

I am having issues trying to map two fields that are foreign keys into the same table. The use case is for a modifier and creator. My class already has the Ids, and then I wanted to add the full User object as virtual.
I am using a base class so that each of my tables have the same audit fields:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
[ForeignKey("CreatedById")]
public virtual User CreatedByUser { get; set; }
[ForeignKey("ModifiedById")]
public virtual User ModifiedByUser { get; set; }
}
The child class is very simple:
public class CircleUserSubscription : Entity
{
[Required]
public long Id { get; set; }
public long SponsorUserId { get; set; }
[ForeignKey("SponsorUserId")]
public virtual User User { get; set; }
public long TestId { get; set; }
[ForeignKey("TestId")]
public virtual User Test { get; set; }
}
This is a standard junction table.
When I try to generate the migration, I am getting errors that I don't understand fully.
Unable to determine the relationship represented by navigation property 'CircleUserSubscription.User' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I tried what this answer had, but the code is basically the same: https://entityframeworkcore.com/knowledge-base/54418186/ef-core-2-2---two-foreign-keys-to-same-table
An inverse property doesn't make sense since every table will have a reference to the user table.
For reference, here is the User entity:
public class User : Entity
{
public long Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I am hoping you all can help me out, TIA :)
EDIT: One thing to note, all of this worked fine when the entity class was as follows:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
}
It was only after I added the entity that things went awry.

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.

Entity Framework DbContext Delete child object

I am trying to delete the child objects in foreach loop but that doesn't seem to be working.. Here is what I have.
I have a meeting and meeting_category entities which has 1-to-many relationship..
foreach (meeting_category meetingCategory in currentMeeting.meeting_category)
{
dbContext.meeting_category.Remove(meetingCategory);
dbContext.Entry(meetingCategory).State = EntityState.Deleted;
dbContext.SaveChanges();
}
I am then returning to the same view with updated results.. This seems to be very inconsistent. Sometimes it deletes entities and sometimes it doesn't. Even when it deletes it, my meeting object still have meeting_category objects I deleted.
When it doesn't delete from DB, it updates the meeting object and removed meeting_category objects from the meeting..
Is there any kind of reset or refresh that I will have to do in order for meeting object to remove the meeting_category objects..
How can I make sure that it consistently deletes the meeting_category objects both from DB and from the meeting object and when I return to the view, I have an updated meeting object?
Here is my meeting entity
public partial class meeting
{
public meeting()
{
this.meeting_questions = new HashSet<meeting_questions>();
this.meeting_abstract = new HashSet<meeting_abstract>();
this.meeting_category = new HashSet<meeting_category>();
this.meeting_image = new HashSet<meeting_image>();
}
public int meeting_id { get; set; }
public int language_id { get; set; }
public string meeting_code { get; set; }
public string meeting_name { get; set; }
public string meeting_description { get; set; }
public System.DateTime meeting_start_date { get; set; }
public System.DateTime meeting_end_date { get; set; }
public System.DateTime abstract_cutoff_date { get; set; }
public string meeting_guidelines { get; set; }
public string created_by { get; set; }
public Nullable<System.DateTime> created_datetime { get; set; }
public Nullable<bool> meeting_published { get; set; }
public Nullable<bool> meeting_deleted { get; set; }
public Nullable<bool> meeting_fully_created { get; set; }
public virtual language language { get; set; }
public virtual ICollection<meeting_questions> meeting_questions { get; set; }
public virtual ICollection<meeting_abstract> meeting_abstract { get; set; }
public virtual ICollection<meeting_category> meeting_category { get; set; }
public virtual ICollection<meeting_image> meeting_image { get; set; }
}
And here is my meeting_category entity
public partial class meeting_category
{
public meeting_category()
{
this.abstract_category = new HashSet<abstract_category>();
}
public int meeting_category_id { get; set; }
public int meeting_id { get; set; }
public int category_type_id { get; set; }
public int category_id { get; set; }
public string category_name { get; set; }
public string category_name_en { get; set; }
public virtual ICollection<abstract_category> abstract_category { get; set; }
public virtual category category { get; set; }
public virtual category_type category_type { get; set; }
public virtual meeting meeting { get; set; }
}
I have a couple of questions about what it is that you are trying to achieve.
Firstly are you sure that the Meeting -> Category relationship is many-to-one? I would normally expect it to be many-to-many, i.e. each Meeting can have many Categories and each Category can be attached to many Meetings.
Secondly, are you actually trying to delete the Category or are you trying to remove a Category from a Meeting?
If you are simply trying to remove the relationship between a Meeting and a Category then you need to edit the navigation property, i.e. MyMeeting.Categories.Remove(MyCategory).
If you are trying to delete the actual Category then you will need to make sure that that Category is not currently linked to any Meeting otherwise you will get a Foreign Key violation if you try to remove the Category.
On top of all of this you may be encountering chaching or simply object lifetime management issues.
What type of application are you creating? ASP.NET? WinForms? etc.
How are you actually instantiating a concrete version of your DBContext? Are you using DI?
Cheers Mike
I managed to fix the issue by creating the DbContext per controller action and destroying it before loading the view.
The problem was that I was creating the DbContext in another class and was reusing the same context on all controller action. Since Entities are cached in dbcontext, I was always getting the old cached copy of entities and was working very inconsistently.

Categories