Table per hierarchy not default behavior of EF6 - c#

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

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 do I set up a one-to-many relationship using Entity Framework Core?

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.

Entity Framework Inheritance: Foreign Key in the same table

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.

Code-First SQL Server ASP.NET MVC6

I am a VB.NET programmer, but I am trying to learn C# and MVC in my spare time. I am using ASP.NET MVC 5.1.0.0 and I am trying to do code-First database creation in a local instance of SQL Server.
I was able to get the first database table to update in the database when I ran Update-Database from within the IDE, but when I added a second table that has a PK/FK relationship with the first, I am getting a red line under [ForeignKey] which reads
Does not contain a constructor that takes 1 arguments
I have been searching all over and not getting anywhere. Any suggestions or help would be appreciated. By the way, the first table is a PK/FK relationship to the AspNetUsers table.
public class BuildDatabase : IdentityUser
{
public virtual Companies Companies { get; set; }
public virtual NotaryProfile NotaryProfile { get; set; }
}
public class Companies
{
[Key]
[Column("CompanyID")] // Did this as the database will reflect TableName_ColumnName instead.
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public bool IsActive { get; set; }
public bool IsNotary { get; set; }
public virtual ICollection<NotaryProfile> NotaryProfile { get; set; }
}
public class NotaryProfile
{
[Key]
public int NotaryID { get; set; }
public string NamePrefix { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public string NameSuffix { get; set; }
public bool IsActive { get; set; }
public int DefaultState { get; set; }
public int DefaultCounty { get; set; }
public bool IsSigningAgent { get; set; }
public bool HasABond { get; set; }
public decimal BondAmount { get; set; }
public bool HasEandO { get; set; }
public decimal EandOAmount { get; set; }
public bool ElectronicNotarizationsAllowed { get; set; }
public string ElectronicTechnologyUsed { get; set; }
public string ComissionNumber { get; set; }
public DateTime CommissionIssued { get; set; }
public DateTime CommssionOriginal { get; set; }
public DateTime CommissionExpires { get; set; }
public DateTime CommissionFiledOn { get; set; }
public string SOSAuditNumber { get; set; }
public string CommissionDesc { get; set; }
[Foreignkey("CompanyID")] // Companies.CompanyID = PK
public int CompanyID { get; set; } // PK/FK relationship.
public Companies Companies { get; set; } // Reference to Companies table above.
}
public class SchemaDBContext : IdentityDbContext<BuildDatabase>
{
public SchemaDBContext()
: base("DefaultConnection"){}
public DbSet<Companies> Companies { get; set; }
public DbSet<NotaryProfile> NotaryProfile { get; set; }
}
One of your classes (probably NotaryProfile) needs to reference another object (the foreign key relationship) but there is no constructor in that class that accepts an argument to establish that relationship, e.g.:
public NotaryProfile(int companyId) {
this.companyId = companyId;
}
BTW, a better way to establish that relationship is to use the actual class type rather than the ID, as in:
public class NotaryProfile {
...
public Company Company { get; set; }
// Instead of this:
// public int CompanyID { get; set; } // PK/FK relationship.
...
}
See also:
C# “does not contain a constructor that takes '1' arguments”
Does not contain a constructor that takes 2 arguments

Categories