I am getting the weirdest error. I'm using code first to initial my database. I have 2 entities that have a many to many relationship. If I attempt to initialize either ICollection in the constructor I get the following error when trying trying to use the context to add a value (initially build the database vie entity framework)
The number of members in the conceptual type 'ClubCraftManager.DataAccess.Club' does not match with the number of members on the object side type 'ClubCraftManager.Model.Models.Club'. Make sure the number of members are the same.
public class Club
{
public Club()
{
this.ClubCrafters = new List<Crafter>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Guid ClubIdGuidId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public Guid ClubMangerId { get; set; }
[ForeignKey("ClubMangerId")]
public virtual Crafter ClubManager { get; set; }
public virtual ICollection<Crafter> ClubCrafters { get; }
}
If I leave the classes as the following no error, but I hate not initialing Collections and or lists, leaves yourself open for null values later on....
public class Club
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Guid ClubIdGuidId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public Guid ClubMangerId { get; set; }
[ForeignKey("ClubMangerId")]
public virtual Crafter ClubManager { get; set; }
public virtual ICollection<Crafter> ClubCrafters { get; set; }
}
Any idea what's going on here...?
Related
I recently needed to change the type of three properties in a model class from string to an ICollection custom type as shown below.
There are also three classes (SpecialType, TypeToAdd, TypeToRemove) that were added that have a primary key ID, name (string), qty (int) and a FK to corresponding Subscriptions_Regular_Id.
I ran the migration, then update-database to script, but when I ran the script in SSMS console it left off the three ICollection properties below. It did create the three dependent tables with their foreign keys back to the parent, but I can't understand why it's not creating these three ICollection properties. Something simple I'm overlooking I'm sure and wanted to get some input if anyone might have a suggestion.
public class Subscriptions
{
[Key]
public int Subscriptions_Regular_Id { get; set; }
public string CustomerNumber { get; set; }
public string Type { get; set; }
public int TypeQty { get; set; }
public ICollection<SpecialType> SpecialType { get; set; }
public ICollection<TypeToAdd> TypeToAdd { get; set; }
public ICollection<TypeToRemove> TypeToRemove { get; set; }
}
For context:
Subscriptions can have many SpecialTypes, TypeToAdd, and TypeToRemove
SpecialTypes, TypeToAdd, TypeToRemove can be tied to only one Subscription.
Thanks in advance for any input.
====== EDIT ======
Adding 3 ICollection classes:
public class TypeToAdd
{
[Key]
public int TypeToAddId { get; set; }
public string TypeToAdd { get; set; }
public int Qty { get; set; }
public int Subscriptions_Regular_Id { get; set; }
public Subscriptions Subscriptions { get; set; }
}
The other two classes are the same as above other than the first two property names (they are TypeToRemove and SpecialType).
but I can't understand why it's not creating these three ICollection properties
Collection Navigation Properties are implemented using seperate tables with foreign keys. Relational databases don't have multi-valued attributes, so that's just how related collections are implemented in an RDBMS.
Try to change the classes to this
public class Subscription
{
[Key]
public int Id { get; set; }
public string CustomerNumber { get; set; }
public string Type { get; set; }
public int TypeQty { get; set; }
[InverseProperty(nameof(TypeToAdd.Subscription))]
public ICollection<TypeToAdd> TypeToAdds { get; set; }
[InverseProperty(nameof(SpecialType.Subscription))]
public virtual ICollection<SpecialType> SpecialTypes { get; set; }
[InverseProperty(nameof(TypeToRemove.Subscription))]
public ICollection<TypeToRemove> TypeToRemoves { get; set; }
}
public class TypeToAdd
{
[Key]
public int Id { get; set; }
public string TypeToAdd { get; set; }
public int Qty { get; set; }
public int SubscriptionId { get; set; }
[ForeignKey(nameof(SubscriptionId))]
[InverseProperty("TypeToAdds")]
public virtual Subscription Subscription { get; set; }
}
SpecialType and TypeToRemove classes should be configured the same way as TypeToAdd.
So I'm currently debating the option of either defining concrete classes with properties, or to go with a metadata-type design. For example:
public class Employee
{
public Guid Id { get; set; }
public string Name { get; set; }
public string EmployeeCode { get; set; }
public string SpecialAssignment { get; set; }
public string SomeFutureProperty { get; set; }
}
Versus a key/value pair design which can be dynamic:
public class Employee
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<MetaKeyValue> Properties { get; set; }
}
public class MetaKey
{
public Guid Id { get; set; }
public string EntityType { get; set; } // could be a dictionary or enum
public string Name { get; set; }
public string Description { get; set; }
public string Required { get; set; }
}
public class MetaKeyValue
{
public Guid Id { get; set; }
public Guid EntityId { get; set; }
public Guid MetaKeyId { get; set; }
public string Value { get; set; } // string isn't the preferred object type
}
So, the debate is that I'm not sure which one is more efficient. The target persistence is a SQL database using Entity Framework. The beauty of the metadata design is that without modifying code and planning a deployment, new "properties" could be added to an entity and the values could be added and retrieved. The negative is that it's not what I'm accustomed to as I am an old-school coder who likes concrete classes that are statically defined. Would the dynamic design bite me in the rear later down the line?
I have struggling to get ICollection value in entity framework. I am using version 6.
Class Navigation_Functions
[Table("Navigation_Functions")]
public class Navigation_Functions
{
public Navigation_Functions()
{}
[Key]
public int Function_ID { get; set; }
[StringLength(250)]
[Required(ErrorMessage = "Required Title")]
[Display(Name = "Function Title")]
public string FunctionName { get; set; }
[Required(ErrorMessage = "Required Hierarchy Level")]
[Display(Name = "Hierarchy Level")]
public int Hierarchy_Level { get; set; }
public ICollection<Navigation_FunctionController> Navigation_FunctionController { get; set; }
}
Class Navigation_Controller
[Table("Navigation_FunctionController")]
public class Navigation_FunctionController
{
public Navigation_FunctionController()
{ }
[Key]
public int ControllerID { get; set; }
[StringLength(250)]
[Required]
public string ControllerName { get; set; }
public ICollection<Navigation_Functions> Navigation_Functions { get; set; }
}
Middle Class to break many-to-many relationship
[Table("Navigation_FunctionInController")]
public class Navigation_FunctionInController
{
public Navigation_FunctionInController()
{
}
[Key]
public int FunctionInController_ID { get; set; }
[Key]
[ForeignKey("Navigation_Functions")]
public int Function_ID { get; set; }
[Key]
[ForeignKey("Navigation_FunctionController")]
public int ControllerID { get; set; }
public Navigation_FunctionController Navigation_FunctionController { get; set; }
public Navigation_Functions Navigation_Functions { get; set; }
}
so when I run following code, I get all navigation_controller for navigation_function
public IEnumerable<Navigation_Functions> GetAllFunctions()
{
using(var _uow = new FunctionsNavigation_UnitOfWork())
{
var entities = _uow.Navigation_Functions_Repository.GetAll();
return entities.ToList();
}
}
I add virtual to model as
public virtual ICollection<Navigation_Functions> Navigation_Functions { get; set; }
public virtual ICollection<Navigation_FunctionController> Navigation_FunctionController { get; set; }
and I am getting following error to read data
You don't need to create the many to many relationship table, Entity framework will do that for you. All you need is to declare your properties as virtual, all use the include method.
more details here or here
Make sure to set ICollection method as "virtual"
e.g.
public virtual ICollection Courses { get; set; }
Here is an example:
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
Keep in mind if the intersection table contains one or more properties (which are not part of the Primary Key), then don't create an intersection table, just use to ICollection in both entities. However, if there is one or more properties in the intersection, then create the intersection class. This is how the EF Designer works.
For a project at work I have created entities similar to the following:
public class ObjectA
{
public Guid ObjectAGUID { get; set; } // key
public string Name { get; set; }
public int Number { get; set; }
}
public class ObjectB
{
public Guid ObjectBGUID { get; set; } //key
public string Name { get; set; }
public int Number { get; set; }
}
public class Note
{
public Guid NoteGUID { get; set; } // key
public Guid AssociationGUID { get; set; }
public string Text { get; set; }
public string NoteType { get; set; }
}
Both ObjectA and ObjectB have a 1-Many relationship with Note where Note.AssociatedGUID is the dependent property to A and B's respective entity key. In other words, A and B can have any number Note entities associate with either one.
My problem:
When I create a new ObjectA and a new Note where Note.AssociatedGUID = ObjectA.ObjectAGUID , I get the following error on DBContext.SaveChanges():
Entities in 'Entities.Notes' participate in the 'ObjectBNote' relationship. 0 related 'ObjectB' were found. 1 'ObjectB' is expected.
Musings
If I want to have Notes for both ObjectA and ObjectB do I need to create separate Note entities,say NoteA and NoteB, to do this? If so this seems redundant.
Or, do I need to have a separate nullable foreign key on Note for each parent entity? While more manageable this seems a little overkill as well.
public class Note
{
public System.Guid NoteGUID { get; set; }
public System.Guid? ObjectAGUID { get; set; }
public System.Guid? ObjectBGUID { get; set; }
public string Text { get; set; }
public string NoteType { get; set; }
}
Help?
I am trying to return as JSON the fully deep object (with all of the foreign key relationships filled in) but I am getting nulls for all the referenced objects.
Here is the call to get the object:
public ActionResult GetAll()
{
return Json(ppEFContext.Orders, JsonRequestBehavior.AllowGet);
}
And here is the Order object itself:
public class Order
{
public int Id { get; set; }
public Patient Patient { get; set; }
public CertificationPeriod CertificationPeriod { get; set; }
public Agency Agency { get; set; }
public Diagnosis PrimaryDiagnosis { get; set; }
public OrderApprovalStatus ApprovalStatus { get; set; }
public User Approver { get; set; }
public User Submitter { get; set; }
public DateTime ApprovalDate { get; set; }
public DateTime SubmittedDate { get; set; }
public Boolean IsDeprecated { get; set; }
}
I have not yet found a good resource on using EF 4.1 Annotations. If you could suggest a good one, that has the answer, you could give me the link and that would be enough of an answer for me!
Regards,
Guido
Update
I added the virtual keyword as per Saxman and am now
dealing with the circular reference
error issue.
Add the virtual keyword before your related entities:
public class Order
{
public int Id { get; set; }
public virtual Patient Patient { get; set; }
public virtual CertificationPeriod CertificationPeriod { get; set; }
public virtual Agency Agency { get; set; }
public virtual Diagnosis PrimaryDiagnosis { get; set; }
public virtual OrderApprovalStatus ApprovalStatus { get; set; }
public virtual User Approver { get; set; }
public virtual User Submitter { get; set; }
public DateTime ApprovalDate { get; set; }
public DateTime SubmittedDate { get; set; }
public Boolean IsDeprecated { get; set; }
}
You might end up with a A circular reference was detected while serializing an object... error if your objects have references of each other. In that case, you will need to create a ViewModel or something similar to overcome this problem. Or use LINQ to project an anonymous object.
Read about Loading Related Objects