Fluent API meaning in ASP.NET MVC when using Entity Framework - entity-framework

I am learning ASP.NET MVC. And In order to create PK and FK I have added some code in models in .cs file as below
public class Courses
{
public int CourseID { get; set; }
[Key]
public string CourseName { get; set; }
public string Description { get; set; }
public int Duration { get; set; }
public virtual ICollection<Instructors> Instructors { get; set; }
}
public class Instructors
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CourseName { get; set; }
[ForeignKey("CourseName")]
public virtual Courses Courses { get; set; }
}
My question is then what is the significance of Fluent API. I have successfully created PK and FK using above code in model. Then what is Fluent API and why it is needed?

Entity framework Fluent Api is an alternative way to define database schema using Entity framework Code First approach. The syntax that you used in your question uses data annotations which is other common approach.
The major advantage of FluentApi is that you don't have to have actual access to your model classes in order to decorate them. For example when you have your models in separate assembly decorating them with annotations is simply impossible. On the other hand by using EF FluentAPI you can easily do it with something like:
modelBuilder.Entity<Courses>().HasKey(c => c.CourseID);
At the bottom line both approaches generate exactly the same database schema.
So if you prefer to use data annotations and your project structure allows it, you can use it without any doubts. In those cases when you can not use the data annotations approach and you still want to use Code First approach, FluentApi is the right way to look at.

Related

.NET Core Entity Framework linking subtable to property

This is an existing .NET Core 3.1 project I inherited.
I have a class referring to a database table
public class SupportContract
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public int SupportContractStatusId { get; set; }
public virtual SupportContractStatus SupportContractStatus { get; set; }
}
and a sub table with a foreign key
public class SupportContractStatus
{
public int Id { get; set; }
public string SupportContractStatusName { get; set; }
}
This works fine I can get
supportContract.SupportContractStatus.SupportContractStatusName
But if I rename SupportContractStatusId to ContractStatusId in C# and the database, I get an error "SupportContractStatusId missing".
I cannot find any link between the column SupportContractStatusId and table SupportContractStatus anywhere in code nor is there any mention of the foreign key.
There is no link in the DbContext either.
Is this naming convention assumed by Entity Framework? How does the framework know of the foreign key?
Yes, the naming convention that EF expects by default is based on the class name, not the property name. It will look for ClassNameId or ClassName_Id. You can link the FK either through annotation or configuration.
I.e.
public int ContractStatusId { get; set; }
[ForeignKey("ContractStatusId")]
public virtual SupportContractStatus ContractStatus { get; set; }
Configuration is done through IEntityTypeConfiguration implementations or by implementing the OnModelCreating method in the DbContext and configuring the relationship within the modelBuilder. For occasional deviations from convention, the attribute approach can generally cover everything.

Defining a "one-to-one-to-one" relationship on Firebird 2.5 EF Core

I'm working with EF Core and a third-party Firebird 2.5 database and, for some reason, they decided to, rather than do a simple one-to-one relationship, create a single table with two columns that do that relationship itself, i.e.
STOCK
========
ID_STOCK(int)
more columns (and their datatypes)
STOCK_IDENTIFIER
========
ID_STOCK (int)
ID_IDENTIFIER (int)
STOCK_PRODUCT
========
ID_IDENTIFIER (int)
more columns (and their datatypes)
So, every STOCK has one STOCK_IDENTIFIER, which, in turn, has one STOCK_PRODUCT. Usually, when I'm creating my own DB in MySQL, I just set foreign keys with data annotations (I'm not fluent in Fluent API, pun intended) and let the migration do its job. However, in this case I can't change the DB's schema (on the account of it being third-party), so I need to use the existing structure.
Right now I have the following:
public class STOCK
{
[Key]
public int ID_STOCK { get; set; }
[MaxLength(50)]
public string DESCRIPTION { get; set; }
[Column(TypeName = "decimal(18, 4)")]
public decimal SELL_PRICE { get; set; }
public STOCK_IDENTIFIER STOCK_IDENTIFIER{ get; set; }
}
public class STOCK_IDENTIFIER
{
[ForeignKey("ID_STOCK")]
public STOCK ID_STOCK { get; set; }
public STOCK_PRODUCT ID_PRODUCT { get; set; }
}
public class STOCK_PRODUCT
{
[ForeignKey("ID_PRODUCT")]
public STOCK_IDENTIFIER ID_IDENTIFIER{ get; set; }
[MaxLength(18)]
public string GTIN{ get; set; }
[MaxLength(18)]
public string SKU{ get; set; }
[Column(TypeName = "decimal(18, 4)")]
public decimal INSTOCK_AMNT { get; set; }
}
I read at The property X is of type Y which is not supported by current database provider that Fluent API could fix that, however, that article works flawlessly for one-to-one. As soon as I try to implement Fluent on a cascading relationship like this one, I get
modelBuilder.Entity<STOCK_IDENTIFIER>()
.HasOne<STOCK_PRODUCT>(p => p.ID_IDENTIFIER)
.WithOne();
modelBuilder.Entity<STOCK>()
.HasOne<STOCK_IDENTIFIER>(p => p.IDENTIFICADOR)
.WithOne();
The property or navigation 'ID_IDENTIFIER' cannot be added to the entity
type 'STOCK_PRODUCT' because a property or navigation with the
same name already exists on entity type 'STOCK_PRODUCT'.
Any hints on what I've been doing wrong?

EF 5 code first optional one to one mapping accessing foreign key fields on the model

This question is basically a repeat of this question regarding EF4 CTP but specific to EF 5.
I have a POCOs set up such that
public class ClassPrinciple
{
public int ClassPrincipleID { get; set; }
public virtual ClassDependent ClassDependent{ get; set; }
}
and
public class ClassDependent
{
public int ClassDependentID { get; set; }
public virtual ClassPrinciple ClassPrinciple{ get; set; }
}
in my model builder I create the optional one to one mapping like this
modelBuilder.Entity<ClassPrinciple>().HasOptional(p => p.ClassDependent)
.WithOptionalDependent(s => s.ClassPrinciple);
this creates, on the ClassPrinciples table a column called ClassDependent_ClassDependentID . I would like to be able to reference the data in this column through a property on the ClassPrinciple model but I seem unable to do so. The web page I linked to at the top of this question states:
EF in general only supports exposing FK properties on your entities in
one:many relationships (unless the FK is also the PK). This is
somewhat artificial but a side effect of EF not supporting non-PK
unique constraints. We are working on support for unique constraints
for EF at the moment but it won't be there in our first RTM of Code
First.
Sorry not to have a better answer as there really isn't a workaround
at this stage.
Is this still the case or is there a way to resolve this. I have tried fluent api map to column and data annotations in all sorts of combinations without success.
use this code :
public class ClassPrinciple
{
public int ClassPrincipleID { get; set; }
public int ClassDependentId { get; set; }
[ForeignKey("ClassDependentId")]
[InverseProperty("ClassPrinciple")]
public virtual ClassDependent ClassDependent{ get; set; }
}
public class ClassDependent
{
public int ClassDependentID { get; set; }
[InverseProperty("ClassDependent")]
public virtual ClassPrinciple ClassPrinciple{ get; set; }
}

EF 5 Code First using Inheritence in the class

I am getting Error when trying to run this code.
Unable to determine the principal end of an association between the
types 'AddressBook.DAL.Models.User' and 'AddressBook.DAL.Models.User'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.
The objective is that i am creating baseClass that has commonfield for all the tables.
IF i don't use base class everything works fine.
namespace AddressBook.DAL.Models
{
public class BaseTable
{
[Required]
public DateTime DateCreated { get; set; }
[Required]
public DateTime DateLastUpdatedOn { get; set; }
[Required]
public virtual int CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedByUser { get; set; }
[Required]
public virtual int UpdatedByUserId { get; set; }
[ForeignKey("UpdatedByUserId")]
public virtual User UpdatedByUser { get; set; }
[Required]
public RowStatus RowStatus { get; set; }
}
public enum RowStatus
{
NewlyCreated,
Modified,
Deleted
}
}
namespace AddressBook.DAL.Models
{
public class User : BaseTable
{
[Key]
public int UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Password { get; set; }
}
}
You need to provide mapping information to EF. The following article describes code-first strategies for different EF entity inheritance models (table-per-type, table-per-hierarchy, etc.). Not all the scenarios are directly what you are doing here, but pay attention to the mapping code because that's what you need to consider (and it's good info in case you want to use inheritance for other scenarios). Note that inheritance does have limitations and costs when it comes to ORMs, particularly with polymorphic associations (which makes the TPC scenario somewhat difficult to manage). http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx
The other way EF can handle this kind of scenario is by aggregating a complex type into a "fake" compositional relationship. In other words, even though your audit fields are part of some transactional entity table, you can split them out into a common complex type which can be associated to any other entity that contains those same fields. The difference here is that you'd actually be encapsulting those fields into another type. So for example, if you moved your audit fields into an "Audit" complext type, you would have something like:
User.Audit.DateCreated
instead of
User.DateCreated
In any case, you still need to provide the appropriate mapping information.
This article here explains how to do this: http://weblogs.asp.net/manavi/archive/2010/12/11/entity-association-mapping-with-code-first-part-1-one-to-one-associations.aspx

Entity Framework 5 inheritance generating as TPT instead of TPH?

I'm trying to implement various tables that inherent a groups table. When I generate the database from the model it comes out as type-per-table instead of type-per-inheritance like I would like.
I have:
Group set to abstract
Each group type table is mapped to Group conditionally when type(column) = a different int for each table
Can anyone point me in the right direction for what I need to do to change this to type per inheritance?
EDIT: by request via comment here is my db set for group, and none of the group types of a dbset
public DbSet<Group> Groups { get; set; }
Here are the generated classes:
Group:
public abstract partial class Group
{
public Group()
{
this.GroupHierarchies = new HashSet<GroupHierarchy>();
this.GroupHierarchies1 = new HashSet<GroupHierarchy>();
this.NetworkActions = new HashSet<NetworkAction>();
this.PermissionAssignments = new HashSet<PermissionAssignment>();
this.UserProfiles = new HashSet<UserProfile>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Acronym { get; set; }
public string Description { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public virtual ICollection<GroupHierarchy> GroupHierarchies { get; set; }
public virtual ICollection<GroupHierarchy> GroupHierarchies1 { get; set; }
public virtual ICollection<NetworkAction> NetworkActions { get; set; }
public virtual ICollection<PermissionAssignment> PermissionAssignments { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
One of the group types:
public partial class HoaManagementCompany : Group
{
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
The other group type, there will be many more in the future but only these two until I get it to work.
public partial class HoaAttorney : Group
{
public string Address { get; set; }
}
When I generate the database from the model...
Are you using Model-First strategy? This unfortunately would make it difficult to get TPH inheritance for your model (which would be easy for Code-First or Database-First strategy).
(Default inheritance mapping for Code-First is TPH, so you should not have your problem with Code-First.)
Out of the box TPH is not available with Model-First. The default inheritance strategy for Model-First is TPT and there is no easy way to switch to TPH in the model designer:
It is possible to map to a TPH inheritance using Model First but you
would have to write your own database generation workflow which is
complex. You would then assign this workflow to the Database
Generation Workflow property in the EF Designer. An easier alternative
is to use Code First.
There is an additional tool from Microsoft - the Entity Designer Database Generation Power Pack - which supports TPH database generation workflow for Model-First. But the problem is that it doesn't look very well maintained (last update from May 2012) and it doesn't support Visual Studio 2012. But if you use VS 2010 you can try it.
You should only use your Groups DBSet for TPH.
Also make sure you aren't adding Table annotations to the poco classes
Try following this blog, it worked for me in the past.
Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH).
Also talks about Table per Type (TPT) and Table per Concrete class (TPC) Inheritances.