I got into trouble in mapping tables with Entity Framework with the relationship is one to many to one.
To make it clear, here's the illustration of table classes
public class Human
{
[Key]
public long ID { get; set; }
[Required(ErrorMessage = "must not be empty!", AllowEmptyStrings = false)]
public string HumanName { get; set; }
public virtual ICollection<HumanFootwear> HumanFootwears { get; set; }
}
The Human footwear class (for grouping)
public class HumanFootwear
{
[Key]
public long ID { get; set; }
[ForeignKey("HumanID"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Human CHumans { get; set; }
public long HumanID { get; set; }
[ForeignKey("FootwearID"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Footwear Footwears { get; set; }
public long FootwearID { get; set; }
}
The footwear table class
public class Footwear
{
[Key]
public long ID { get; set; }
[Required(ErrorMessage = "must not be empty!", AllowEmptyStrings = false)]
public string BrandName { get; set; }
}
I'm trying with the fluent API method, but I can't get make it to work
modelBuilder.Entity<Human>()
.HasKey(key => key.ID)
.HasMany(hm => hm.Footwear)
.WithMany(wm => wm.Human)
.Map(map =>
{
map.MapLeftKey("")
});
I get a syntax error on "with many human",
Cannot convert single Human class to ICollection<Human>
Am I doing it wrong? Should I map the human footwear instead?
Related
I'm a little new to code-first in EF Core and I'm trying a few things out and I'm a little confused how to implement the below (or indeed whether it can be implemented or not).
In my model I have a class that maps entities to cases, with the following mapping class
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public Guid EntityId { get; set; }
public EntityModel Entity { get; set; }
}
I am now implementing the EntityModel object. However an entity can be either a Person or a Company. Both these have common properties, but there are some natural differences. What I wanted to do is create an IEntityModel interface and two classes as below
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public Guid EntityId { get; set; }
public IEntityModel Entity { get; set; }
}
public interface IEntityModel
{
Guid EntityId { get; set; }
PostalAddress PrincipalAddress { get; set; }
}
public class CompanyEntity : IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid EntityId { get; set; }
public string CompanyName { get; set; }
public PostalAddress PrincipalAddress { get; set; }
}
public class PersonEntity : IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid EntityId { get; set; }
public PostalAddress PrincipalAddress { get; set; }
public string FirstNames { get; set; }
public string Surname { get; set; }
}
When I try to build this I get the error
The property 'CaseEntity.Entity' is of an interface type ('IEntityModel'). If it is a navigation, manually configure the relationship for this property by casting it to a mapped entity type.
Otherwise, ignore the property using the [NotMapped] attribute or 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I'm not 100% certain I can do what I'm trying to do. Searching around has left me a little confused (is that a solution to implement kind of functionality like, or should I use implement an entity class that has all the properties need to support a Company or a Person?)
I think it would be better if you create a base class
public class EntityModel:IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EntityId { get; set; }
publlic PostalAddress PrincipalAddress { get; set; }
}
CompanyEntity
public class CompanyEntity : EntityModel
{
public string CompanyName { get; set; }
}
CaseEntity
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public int EntityId { get; set; }
public virtual EntityModel EntityModel { get; set; }
}
I am using Entity framework. I am using inheritance, which puts different object types in the same table (via discriminator).
However, this causes an issue as relationships between objects in the same table can not be illustrated via a foreign key. Any suggestions how to solve? Some code below.
public abstract class DivBase
{
public int Id { get; set; }
[Required]
public DateTimeOffset DateCreated { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public DateTimeOffset DateModified { get; set; }
[Required]
public int ModifiedByUserId { get; set; }
}
public abstract class DivClaim : DivBase
{
[Required]
[MaxLength(256)]
public string ClaimType { get; set; }
[Required]
[MaxLength(256)]
public string Name { get; set; }
[MaxLength(10000)]
public string Description { get; set; }
public ICollection<DivUserClaim> UserClaims { get; set; }
}
public class DivCustomer : DivClaim
{
public ICollection<DivProject> Projects { get; set; }
}
public class DivProject : DivClaim, IDivEvent
{
public int CustomerId { get; set; }
public DivCustomer Customer { get; set; }
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset EndDate { get; set; }
}
In this case where your base class just defines common attributes for all your entities, simply exclude the base class from the DbContext. Each of your Entities will get its own table, but they will all have the properties inherited from the base class. You just won't be able to query over the base entity type.
I have this scenario where i have a model named Category that has a One-To-One relation with another model named Question. The following is the code for both of the models:
Category:
public class Category
{
[Key]
[Required]
public int Id { get; set; }
[Required]
public int QuestionRef { get; set; }
[Required]
public string Name { get; set; }
[Required]
public DateTime Timestamp { get; set; }
public virtual Question Question { get; set; }
}
Question:
public class Question
{
[Required]
[Key]
public int Id { get; set; }
[Required]
public int CategoryRef { get; set; }
[Required]
public int QuestionLevel { get; set; }
[Required]
public string QuestionText { get; set; }
[Required]
public DateTime Timestamp { get; set; }
public virtual Category Category { get; set; }
}
Snippet from OnModelCreating:
modelBuilder.Entity<Category>().HasOne(x => x.Question).WithOne(x => x.Category).HasForeignKey<Question>(x => x.CategoryRef);
modelBuilder.Entity<Question>().HasOne(x => x.Category).WithOne(x => x.Question).HasForeignKey<Category>(x => x.QuestionRef);
I seem to have come across a problem that i cannot understand how to tackle. Basically, i do not have a clue of how i can insert this relation into the database (SQL Server).
The question is do i have to implicitly write in the repository that
NewCategory.Question = QuestionInput;
or does it automatically generate itself given the relations i have implied in the OnModelCreating?
I want that UserMessage entity point with ReciverIdFK to SharedManWoman entity and with SenderIdFK to another SharedManWoman entity
public class SharedManWoman
{
public List<UserMessage> UserMessages { get; set; }
}
public class UserMessage
{
[Key]
public long Id { get; set; }
[ForeignKey("UserMessages")]
public long SenderIdFK { get; set; }
[InverseProperty("UserMessages")]
public virtual SharedManWoman UserMessages { get; set; }
[ForeignKey("UserMessages")]
public long ReciverIdFK { get; set; }
[InverseProperty("UserMessages")]
public virtual SharedManWoman UserMessages { get; set; }
}
Well, first of all, you can't have two properties with the same name.
But, using the following fluent api on at least one of the properties should do the job:
modelBuilder.Entity<UserMessage>()
.HasOptional(t => t.UserMessages)
.WithMany()
.WillCascadeOnDelete(false);
EDIT
If you want to do it with annotations, the following should do the job. Note that your SharedManWoman object needs an Id. Also, as it stands, the SharedManWoman's pretty much useless since it doesn't have any properties of its own.
public class SharedManWoman {
public long Id { get; set; }
[InverseProperty("Sender")]
public ICollection<UserMessage> SenderMessages { get; set; }
[InverseProperty("Receiver")]
public ICollection<UserMessage> ReceiverMessages { get; set; }
}
public class UserMessage {
[Key]
public long Id { get; set; }
// Note that these are NULLABLE
public long? SenderIdFK { get; set; }
public long? ReceiverIdFK { get; set; }
[ForeignKey("SenderIdFK")]
public virtual SharedManWoman Sender { get; set; }
[ForeignKey("ReceiverIdFK")]
public virtual SharedManWoman Receiver { get; set; }
}
More Info Here
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.