Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.
Related
I need to update a child list from a parent adding records to it or updating one of its attributes. I receive the updated model from the Controller but when I try to replace the actual list with the new and save the changes to DB I get the error:
The instance of entity type 'WorkflowReferenciaExecucoes' cannot be tracked because another instance with the same key value for {'ReferenciaExecucoesId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
I don't have access to the dbContext directly because we are using the repository pattern. What I have tried to update the child in the service is:
private void Update(Workflow entity)
{
// entity is my updated model received by controller
// Getting the actual parent in the database
var workflow = GetById(entity.WorkflowId);
workflow.NomeWorkflow = entity.NomeWorkflow;
workflow.DescricaoWorkflow = entity.DescricaoWorkflow;
workflow.FgAtivo = entity.FgAtivo;
// Updating child list
workflow.WorkflowReferenciaExecucoes = entity.WorkflowReferenciaExecucoes;
// Trying to save the update gives error
_uow.WorkflowRepository.Update(entity);
}
My parent class is:
public class Workflow
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int WorkflowId { get; set; }
public int ProjetoId { get; set; }
public int WorkflowTipoId { get; set; }
public string NomeWorkflow { get; set; }
public string DescricaoWorkflow { get; set; }
public DateTime DataInclusao { get; set; }
public bool FgAtivo { get; set; }
public Projeto Projeto { get; set; }
public WorkflowTipo WorkflowTipo { get; set; }
public IEnumerable<WorkflowReferenciaExecucao> WorkflowReferenciaExecucoes { get; set; }
public IEnumerable<WorkflowCondicaoExecucao> WorkflowCondicaoExecucoes { get; set; }
}
And child class:
public class WorkflowReferenciaExecucao
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ReferenciaExecucaoId { get; set; }
public int WorkflowId { get; set; }
public int? ExecucaoWorkflowId { get; set; }
public int ValorReferenciaExecucao { get; set; }
public bool FgProcessar { get; set; }
public bool FgAtivo { get; set; }
}
What do I have to do to update the actual list to the new one?
Thank you!
Could it be that the passed in entity has duplicates in the WorkflowReferenciaExecucoes property - meaning the same WorkflowReferenciaExecucao exists twice in that IEnumerable?
you can not update like that you have wrong relationship you class should be like that
public class WorkflowReferenciaExecucao
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ReferenciaExecucaoId { get; set; }
public Workflow Workflow { get; set; }
public int? ExecucaoWorkflowId { get; set; }
public int ValorReferenciaExecucao { get; set; }
public bool FgProcessar { get; set; }
public bool Fugitive { get; set; }
}
WorkflowReferenciaExecucao is one and it has only one workflow so when you update Workflow then you have to update only workflow id in WorkflowReferenciaExecucao don't pass whole object just pass id to change it one to many relationship so on one side you update anything it don't relate to many relationship because it only point to id that it
I can reproduce your problem when there are multiple child records with the same ReferenciaExecucoesId in the update entity.
You can check if this is the case.
For example if I have a model:
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
}
public class PaymentPolicy : BasePolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy : BasePolicy {
public int ReturnTerm { get; set; }
}
... and want to create codefirst database and a repository with next requirements:
ability to retrieve base entities by Id in base type (BasePolicy). This is necessary for admin index page which displays list of policies only by it's name.
I need to have access to children specific properties (PaymentMethod if it is PaymentPolicy - etc.) using select by Id . This is necessary for edit actions.
What is the best way to do that? Should I create seperate table for each child type?
public class Database : DbContext
{
public DbSet<PaymentPolicy> PaymentPolicies { get; set; }
public DbSet<ReturnPolicy> ReturnPolicies { get; set; }
}
+ data is logically sorted
- I will not be able to get BasePolicy entity by it's unique id without joining those tables and specifying policy type in select query. That's why I should inject some PolicyType enum to base type and implement repository method which will get BasePolicy by it's type (to determine which table to get from) and only then by unique Id - and downcast BasePolicy to specific child type policy. This is the solution I'm using just now.
... should I remove inheritance at all?
public class PaymentPolicy {
public int Id { get; set; }
public string Name { get; set; }
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int Id { get; set; }
public string Name { get; set; }
public int ReturnTerm { get; set; }
}
+ data is still logically sorted
- I still will not be able to get BasePolicy entity by it's unique id.
... should I add child types as navigation properties to base type?
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
public PaymentPolicy PaymentPolicy { get; set; }
public ReturnPolicy ReturnPolicy { get; set; }
}
public class PaymentPolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int ReturnTerm { get; set; }
}
- This will destroy logic model structure
+ I will be able to get list of policies without redundant joins
+ It will provide strong one to one relationship
Or are there some more advanced strategies and techniques?
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.
So, i have this class here:
public class Platillo
{
public virtual int ID { get; set; }
public virtual String NombrePlatillo { get; set; }
public virtual int idRestaurante { get; set; }
public virtual String DescripcionPlatillo { get; set; }
public virtual bool esAprobado { get; set; }
public virtual bool esDisponible { get; set; }
public virtual double precio { get; set; }
public virtual DateTime vigenciaPlatillo { get; set; }
public virtual List<ListaIngredientes> listadeIngredientes { get; set;}
}
I've created a strongly typed PlatilloController that makes all basic CRUD operations. The problem is, the View renderes everything but the List.
My idea is to create a List that allows to add new ingredients(Ingredientes) and the amount of servings (Porciones) for each one on a dish (Platillo).
public class ListaIngredientes
{
public virtual int ID { get; set; }
public virtual Ingrediente ingrediente { get; set; }
public virtual int porciones { get; set; }
}
public class Ingrediente
{
public virtual int ID { get; set; }
public virtual String NombreIngrediente { get; set; }
//...
}
So, what i was thinking was to implement a PartialView that rendered a list of every ingredient on the dish, and that allowed to add new ingredients. How exactly do I do that? And, since i plan on creating and updating new ingredients on the same page, i'm sure i should be taking AJAX into account. How exactly can i use Ajax to Create and display ListaIngrediente's list entries?
Just a sample using a partial view page, try this:
#model <Project>.Models.Platillo
#foreach(ListaIngredientes ing in listadeIngredientes)
{
<div>#ing.ID</div>
<div>#ing.Ingrediente.NombreIngrediente</div>
}
I am alittle bit confused about your design why would you use a list public
virtual List<ListaIngredientes> listadeIngredientes { get; set;} I would start but first creating a Platillo foreign key in your ListaIngredientes that would match with Platillo something like PlatilloID so now you would have a list of ListaIngredientes that match the Platilloios and it ingridients.
and then sure you can create an ajax partial view at which you can add Ingrediente and then match specific ingridients with your Platilloio on a separate view in another word create separately ingridiets and Platilloio and then on another view add ingridiets from the ingridients in your Ingridients table to Pelatio.
i have 2 entities each with a relating c# class. I set up a navigation property on table A to contain a reference to many items in table B. When i make a new table A class object i need to be able to create the collection of table B objects in table A. How do i set up the navigation property in the table A c# class?
DATAMODEL:
http://bluewolftech.com/mike/mike/datamodel.jpg
Navigation properties are simple in EF. The example below shows how a navigation property would look:
public class Foo
{
public int FooId { get; set; }
public string SomeProperty { get; set; }
public virtual IEnumerable<Bar> Bars { get; set; }
}
Where Foo represents tableA and Bar represents tableB. They key word for the navigation property is virtual which enables lazy-loading by default. This is assuming you're using EF4.1 Code First.
EDIT
Off the top of my head, this should be a good starting template for you:
public class PointOfInterestContext : DbContext
{
public IDbSet<PointOfInterest> PointOfInterest { get; set; }
public IDbSet<POITag> POITag { get; set; }
public IDbSet<Tag> Tag { get; set; }
public override OnModelCreating(DbModelBuilder modelBuilder)
{
// custom mappings go here
base.OnModelCreating(modelBuilder)
}
}
public class PointOfInterest
{
// properties
public int Id { get; set; }
public string Title { get; set; }
// etc...
// navigation properties
public virtual IEnumerable<POITag> POITags { get; set; }
}
public class POITag
{
// properties
public int Id { get; set;}
public int PointOfInterestId { get; set; }
public int TagId { get; set; }
// navigation properties
public virtual PointOfInterest PointOfInterest { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag
{
// properties
public int Id { get; set; }
public string TagName { get; set; }
// etc...
// navigation properties
public virtual IEnumerable<POITags> POITags { get; set; }
}
Then you would implement the other logic in your business objects. The entities are supposed to be lightweight and at most should have data attributes. I prefer to use the fluent mappings through the OnModelCreating though.
Here are a few good references:
MSDN - EF 4.1 Code First
Code First Tutorial