Entity Framework Core TPH Inheritance 2 sub Classes related to Other Model - asp.net-core

I am devoloping an Asp.Net Core 3 App with Entity Framework Core.
I have a problem with Inheritance and I am not sure how to accomplish what I need.
My Models:
public abstract class Person
{
public int Id {get; set;}
public string name {get; set;}
}
public class Renter: Person
{
public string address{get; set;}
public ICollection<Invoice> Invoices{get;set;}
}
public class UserProfile: Person
{
public string BankAccount {get;set;}
public ICollection<Invoice> Invoices{get;set;}
}
public class Invoice
{
public DateTime Date {get;set;}
public Renter Renter {get; set;}
[Required]
public int RenterId {get; set;}
public UserProfile UserProfile{get; set;}
[Required]
public int UserProfileId {get; set;}
}
Right Now I get a Database Exception: Foreign Key Constraint Fails : RenterId References Person.Id .
Can I Use Fluent Api to manually configure my Setup?
The problem is that the Invoice needs both a Renter and a UserProfile, but Person.Id is the Primary Key for both Renter and UserProfile.
Any help is gratefully appreciated.

Yes, you can use fluent API. Assuming that you are using Table per Type (TPT):
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Renter>().ToTable("Renter");
modelBuilder.Entity<UserProfile>().ToTable("UserProfile");
}
See: https://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx

Related

cant create a relationship between application user table and my tables

I'm using entity framework code first. The below keeps kicking out the unable to determine the principal end of an association. Basically I can't figure out how to get one to many relationships between the auto generated identity table and my own tables with code first.
public class applicationUser : Identity
{
public User user {get;set;}
}
//and then a dependant class called User
public class User
{
public in Id {get;set;}
public string Name {get;set;}
[ForeignKey("Identity")]
public string IdentityId {get;set;}
public ApplicationUser Identity {get;set;}
public string UserPicLocation {get;set;}
}
You're using [ForeignKey()] wrong. The value of [ForeignKey()] should be the name of the property that contains the key of the referenced object.
You should also mark the property that contains the key in the referenced object as the private key with [Key]
Try this:
public class applicationUser : Identity
{
public int UserId {get; set;}
[ForeignKey("UserId")]
public User user {get;set;}
}
and then another class called User
public class User
{
[Key]
public int Id {get;set;}
public string Name {get;set;}
public string IdentityId {get;set;}
public ApplicationUser Identity {get;set;}
public string UserPicLocation {get;set;}
}
I fixed it by setting the primary key as both the primary and foreign key in the dependant table

Entity Framework - Dropped a foreign key column successfully from table but getting an error while accessing the table

I am using a code first method to generate database. My models are as follows -
public class Employee
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
[ForeignKey("ReferenceTbl1")]
public int Reference1Id {get; set;}
// Navigation property
public virtual Reference1 ReferenceTbl1 {get; set;}
}
public class Reference1
{
public int Id {get; set;}
public string Property1 {get; set;}
public string Property2 {get; set;}
}
The tables were created successfully using migration. The data was in both the tables.
Then after couple of months for some reason I had to change the schema. I had to create other table called Reference2. Drop the foreign key and column named "Reference1Id" from the table "Employee". And introduce another foreign key pointing to table "Reference2" in "Employee". So I made following changes in model
public class Employee
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
[ForeignKey("ReferenceTbl1")]
public int Reference1Id {get; set;}
// New foreign key
[ForeignKey("ReferenceTbl2")]
public int Reference2Id {get; set;}
// Navigation property
public virtual Reference1 ReferenceTbl1 {get; set;}
// New navigation property
public virtual Reference2 ReferenceTbl2 {get; set;}
}
public class Reference2
{
public int Id {get; set;}
public string Property3 {get; set;}
public string Property4 {get; set;}
}
I successfully dropped the old foreign key and column from table "Employee" by creating new migration as follows
public override void Up()
{
DropForeignKey("dbo.Employee", "Reference1Id","dbo.Reference1");
DropIndex("dbo.Employee", new[] { "Reference1Id" });
DropColumn("dbo.Employee", "Reference1Id");
}
public override void Down()
{
AddColumn("dbo.Employee","Reference1Id",
e=>e.String(nullable:false,defaultValue: ""));
CreateIndex("dbo.Employee", "Reference1Id");
AddForeignKey("dbo.Employee", "Reference1Id",
"dbo.Reference1", "Id", cascadeDelete: true);
}
So after I ran the command "Update-database" in package manager console, the "Employee" table was updated exactly as I wanted with new foreign key column "Reference2Id" and no column with name "Reference1Id". I also altered the data appropriately.
But now when I try to access the table "Employee", it gives me this error "Invalid column name 'Reference1Id'".
The column "Reference1Id" is not present in the table "Employee" then why would this error occur?
I would really appreciate some help here.
Thanks

Castle Active Record - Nested Data Column Prefix

I have a few classes structured similar to those shown below.
[ActiveRecord]
public class Request : ActiveRecordBase
{
[PrimaryKey]
public int Id {get; set;}
[Nested("SectionA")]
public SectionA A {get; set;}
[Nested("SectionB")]
public SectionB B {get; set;}
}
public class SectionA
{
[Property]
public string Description {get; set;}
[Property]
public string Remark {get; set;}
[HasMany(typeof(Attachment),
Table="Attachments", ColumnKey="RequestId",
Where="Section = 'SectionA'")]
public IList Attachments {get; set;}
}
public class SectionB
{
[Property]
public string Description {get; set;}
[HasMany(typeof(Attachment),
Table="Attachments", ColumnKey="RequestId",
Where="Section = 'SectionB'")]
public IList Attachments {get; set;}
}
[ActiveRecord]
public class Attachment
{
[PrimaryKey]
public int Id {get; set;}
[BelongsTo("RequestId")]
public Request Owner {get; set;}
[Property]
public string Section {get; set;}
[Property]
public string FilePath {get; set;}
}
Everything works fine, except that the columns for Attachment Class will have the prefix as well. And it happens quite randomly, as in some time it does have the prefix and sometime it doesn't.
Is there any way to prevent the Attachment from having the prefix, or is there a better way to structure my classes that prevent this issues.
Seems like way is prevent the nested prefix on Attachment class is to connect Request & Attachment directly. Still need to observe for a few iteration.
[ActiveRecord]
public class Request : ActiveRecordBase
{
[PrimaryKey]
public int Id {get; set;}
[HasMany(typeof(Attachment)]
public IList Attachments {get; set;}
[Nested("SectionA")]
public SectionA A {get; set;}
[Nested("SectionB")]
public SectionB B {get; set;}
}

Building application with Entity framework dbContext API issues

I am developing a WCF Service application. It is going to be a part of large system. It provides some business logic and is based on Entity framework 4.1. I want to divide application code into 2 tiers (projects in VS, dll's): Service (which contains business logic) and DAL.
I have such database model in my project
ClassModel
classID : int, PK
classIdentity : string
teacherName : string
statisticInfo : int
isRegistered : bool
StudentModel
studentID : int, PK
studentIdentity : string
classID : int, FK
For this I am generating code using dbContext templates and I get:
public partial class ClassModel
{
public ClassModel()
{
this.Student = new HashSet<StudentModel>();
}
public int ClassID { get; set; }
public string ClassIdentity { get; set; }
public string TeacherName { get; set; }
public int StatisticInfo { get; set; }
public bool IsRegistered { get; set; }
public virtual ICollection<TerminalModel> Terminal { get; set; }
}
public partial class StudentModel
{
public int StudentID { get; set; }
public string StudentIdentity { get; set; }
public bool IsRegistered { get; set; }
public virtual ClassModel Class { get; set; }
}
I want to expose only some of this information through the service, so I have different model as a data contract:
[DataContract]
public class Clas{
[DataMember]
public string ClassIdentity {get;set;}
[DataMember]
public string TeacherName {get;set;}
[DataMember]
public string ClassMark {get;set;} //computed from statisticInfo
[DataMember]
public int NumberOfStudents {get;set;} //amount of students in this class
}
And my part of my ServiceContract:
[OperationContract]
public void RegsterClass(Clas clas); //(if given clas does not exists adds it and) sets its isRegistered column to True
[OperationContract]
public Clas GetClass(string classIdentity);
As you can see some fields are not present, others are being computed.
In such case I have some concerns about how should I built application properly. Could you write example code which implements the interface methods using everything I mentioned in the way that you think is proper?
Try using T4 templates
It is possible to use T4 templates to generate the dbContext classes, the data transfer objecs (more on that later), the interface as well as all the two methods you have there for each entity in your model: RegsterClass and GetClass. (this would translate to RegsterStudent, GetStudent, and so on for every entity)
Then you can use AutoMapper on NuGet to map from Clas to ClassModel.
I've implemented something similar. I don't pass any of my dbcontext based entities across the wire. I use Data transfer objects for each entity. So a Toyota entity, has a ToyotaDto that has the data annotations and is used for all the WCF CRUD operations. When "Getting" a toyotaDto, I map Toyota to ToyotaDto and return the Dto, when saving, I map the Dto to an entity, of course deleting is done by key, so no Dto necessary.
There are several(1) good(2) examples(3) online you can modify to suit, and if you want I can paste in some of the templates I'm using.

Configuring one to 0 or 1 relation in a relation table using fluent nhibernate

Here are my classes:
public class User {
public virtual int Id { get; private set;}
public virtual IList<Bike> { get; set;}
}
public class Bike {
public virtual int Id { get; private set;}
public virtual string color { get; set;}
}
public class Accident{
public virtual int Id { get; private set;}
public virtual User User{ get; set;}
public virtual Bike Bike{ get; set;}
}
And my tables
User: Id
Bike: Id, color, user(fk)
Accident: Id
AccdentOccurance: AccidentId, UserId, BikeId
An accident can be related to a bike(implicit to the user of the bike), or to a user, but not a bike.
My question is how do I configure the Accident ClassMap to work with the AccidentOccurance table?
Hope you can help.
Lets see if I can get this right so it is helpful to you.
1. On the 3rd line, you left out "Bike" for the name you are assigning the
relation to.
2. Lines 4, 10 & 11, you were missing the reverse mappings.
I added them with the following assumptions:
a. A user can ride more than 1 bike.
b. A user can be in more than 1 accident.
c. A bike can be involved in more than 1 accident.
d. A bike can only be used by 1 user.
If you need the bike to be able to be used by more than 1 user
change line 10 to: public virtual IList<User> User { get; set;}
This will give you a Many to Many relationship.
3. I would merge the tables Accident and AccidentOccurance into 1 table
"Accident". Since if you kept them separated, you are looking at a 1 to 1
relationship that does not offer any special benefits. With the vast
majority of all 1 to 1 relationships, it is best to merge the tables to
limit the SQL queries and speed up your queries on large tables.
public class User {
public virtual int Id { get; private set;}
public virtual IList<Bike> Bike { get; set;} // Modified
public virtual IList<Accident> Accident { get; set;} // Added
}
public class Bike {
public virtual int Id { get; private set;}
public virtual string color { get; set;}
public virtual User User { get; set;} // Added
public virtual IList<Accident> Accident { get; set; } // Added
}
public class Accident{
public virtual int Id { get; private set;}
public virtual User User{ get; set;}
public virtual Bike Bike{ get; set;}
}