Entity Framework Inheritance: Foreign Key in the same table - c#

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.

Related

EF Core Fluent API For Base Class Setting FK

I am trying to set up audit properties for each of my Entities with an abstract Base class
public abstract class Base
{
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public int CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
public int ModifiedByUserId { get; set; }
[ForeignKey("ModifiedByUserId")]
public virtual User ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
Somehow the Data Annotations doesn't work in EF Core but was working in my EF 6 Project
I am now receiving this error:
Unable to determine the relationship represented by navigation 'Address.CreatedBy' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
These are my models:
public class Address : Base
{
public int Id { get; set; }
public string StringAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User : Base
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string Email { get; set; }
public string ContactNumber { get; set; }
public string SecondaryContactNumber { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
public HashSet<Address> Addresses { get; set; }
}
What's weird is when I remove the Base inheritance from my other entities apart from User, EF Core is able to set the FK without any errors.
How do I configure it manually with Fluent API?
I already have a BaseConfig class as starting point to be inherited by my other entity config classes:
public class BaseConfig<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : Base
{
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.Property(x => x.DateCreated).HasDefaultValueSql("GETDATE()");
builder.Property(x => x.DateModified).HasDefaultValueSql("GETDATE()");
// Am I setting this correctly?
builder
.HasOne(b => b.CreatedBy)
.WithMany()
.HasForeignKey(p => p.CreatedByUserId);
}
}

CodeFirst EF Core - Implementing interfaces possible?

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; }
}

How should I create this relationship in Entity Framework?

In my previous question, I've mentioned that I'm developing a Point of Sale application. The platforms I use are WPF, MVVM and Entity Framework (code-first). Since Entity Framework code-first has its own logic to map entities and relations, I'm confused about a case.
I have an EntityBase class:
public class EntityBase
{
public DateTime? CreatedAt { get; set; }
public User CreatedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
public User UpdatedBy { get; set; }
}
public class User : EntityBase
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
Since User class has EntityBase class members, will it arise problems at database side?
Or should I keep the data like this:
public class EntityBase
{
public DateTime? CreatedAt { get; set; }
public int CreatedByUserId { get; set; }
public DateTime? UpdatedAt { get; set; }
public int UpdatedByUserId { get; set; }
}
Create your models in this way:
public class EntityBase
{
public DateTime? CreatedAt { get; set; }
public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public User CreatedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
public int UpdatedById { get; set; }
[ForeignKey("UpdatedById")]
public User UpdatedBy { get; set; }
}
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}

Get ICollection data for many-to-many relationship in Entity framework

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.

Table per hierarchy not default behavior of EF6

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; }
}

Categories