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; }
}
Related
I'm working on a trucking API using Entity Framework (EF) Core. Basic CRUD operations are working fine using the repository pattern. There is an error in
configurations I am implementing, however.
I want to obtain multiple trailers and trucks associated with single load, reflecting the one-to-many relationship.
public class LoadConfiguration : IEntityTypeConfiguration<Load>
{
public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<Load> builder)
{
builder.Property(p=>p.Id).IsRequired();
builder.HasOne(t=>t.Customer).WithMany().HasForeignKey(p=>p.CustomerId);
builder.Property(p=>p.LoadedFrom).IsRequired();
builder.HasMany(p=>p.Trailer).WithOne().HasForeignKey(t=>t.TrailerId);
builder.HasMany(p=>p.Truck).WithOne().HasForeignKey(t=>t.TruckId);
builder.Property(p=>p.Destination).IsRequired();
}
}
public class Truck:BaseEntity
{
public int PlateNo { get; set; }
public string ModelName { get; set; }
public Location StateCode { get; set; }
public int PollutionCertificateValidity { get; set; }
public int DateOfPurchase { get; set; }
public int FitnessCertificateValidity { get; set; }
}
public class Load:BaseEntity
{
public Customer Customer { get; set; }
public int CustomerId { get; set; }
public string LoadedFrom { get; set; }
public Trailer Trailer { get; set; }
public int TrailerId { get; set; }
public Truck Truck { get; set; }
public int TruckId { get; set; }
public string Destination { get; set; }
}
public class Trailer:BaseEntity
{
public int TrailerCapacity { get; set; }
public Truck Truck { get; set; }
public int TruckId { get; set; }
}
public class BaseEntity
{
public int Id { get; set; }
}
A one-to-many relationship is defined by using navigation collections, that has the capacity to hold many Trucks and Trailers. You can choose the collection type freely, but I would suggest ICollection generic type.
Modify your Load class as follows:
public class Load:BaseEntity
{
public Customer Customer { get; set; }
public int CustomerId { get; set; }
public string LoadedFrom { get; set; }
public string Destination { get; set; }
// navigation collections
public ICollection<Trailer> Trailers { get; set; }
public ICollection<Truck> Trucks { get; set; }
}
You will then be able to set up the relationship in your LoadConfiguration class by using
the pluralized name:
builder.HasMany(p=>p.Trailers).WithOne();
builder.HasMany(p=>p.Trucks).WithOne();
.. even though EF Core will be smart enough to figure out the relation by convention so the fluent configuration is redundant.
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 two models.
BdoSubSystem:
public class BdoSubSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
}
And BdoSystem:
public class BdoSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<BdoSubSystem> SubSystems { get; set; }
}
I used migration to create the tables automatically on Azure. The problem is that subsystem is not specific for each system, a subsystem may have multiple parents and can appear in more than one system. But in this way, each subsystem belongs to each system.
How can a subsystem appear in multiple systems?
Good, thanks you all. The solution is to reference in subsystem and use [JsonIgnore]
public class BdoSubSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
public virtual ICollection<BdoSystem> SubSystems { get; set; }
}
If I well understand, SubSystem is just a king of System that with a System as parent ?
If my sentence is true, you can use Self Referencing
public class BdoSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int? ParentSystemId { get; set; }
public virtual BdoSystem ParentSystem { get; set; }
}
However, if you want to have two seperates objects, you should add the navigation propertie in both classes
public class BdoSubSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<BdoSystem> Systems { get; set; }
}
public class BdoSystem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<BdoSubSystem> SubSystems { get; set; }
}
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'm trying to map these three classes to one EF table. In this scenario, my base class actually has a base Entity class, is this causing my issue? I'm not finding any examples that cover a scenario where the default behavior isn't handled properly.
Base Class:
public abstract class Connection : Entity
{
public override int Id { get; set; }
public ContactEnums.ConnectionType Type { get; set; }
public string Value { get; set; }
}
Child Classes:
public class BusinessConnection : Connection
{
[ForeignKey("Business")]
public int BusinessId { get; set; }
public Business Business { get; set; }
}
public class ContactConnection : Connection
{
[ForeignKey("Contact")]
public int ContactId { get; set; }
public Contact Contact { get; set; }
}
Entity Base class:
public abstract class Entity : EqualityAndHashCodeProvider<Entity, int>
{
public override int Id { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string UpdatedBy { get; set; }
public DateTime UpdatedDate { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
}