Entity Framework POCO Relationships - asp.net-mvc-3

I am trying to implement code-first approach of entity framework. I have four entities UserInfo, Client, Admin and Account. I want relationships as:
Each Client has a UserInfo
Each Admin has a `UserInfo
Each Account is linked with a User(UserInfo)
Assuming these things i wrote the POCO models. With the relationships i want, is it correct ?Am i missing something?
public class UserInfo
{
public int UserInfoID { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public Contact Contact { get; set; }
}
public class Admin
{
public int AdminID { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}
public class Client
{
public int ClientID { get; set; }
public CompanyDetails CompanyDetails { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}
public class Account
{
public int AccountID { get; set; }
[Required, Column("Balance"), Display(Name = "Account Balance")]
public double Balance { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}

What you have appears to be correct based on your requirements however I personally prefer the Entity Framework Model Builder when configuring your entities with Code First.
Using the model builder means that you don't have any attributes on your POCO entities which in turn means that you don't need an EF reference to use the entities.
Take a look at my article here for some more info on how to use the modelbuilder : http://blog.staticvoid.co.nz/2012/07/entity-framework-navigation-property.html

Related

Entity History is not working in aspnetboilerplate

I am using aspnetboilerplate and added below configuration in preintiliaze in module. I have also added data annotation Audited to my entity but still it is not working. My entity is inheriting from AuditedEntity as don't need deleted feature. Please help
Configuration.EntityHistory.IsEnabled = true; Configuration.EntityHistory.Selectors.Add(new NamedTypeSelector("Abp.AuditedEntities", type => typeof(AuditedEntity).IsAssignableFrom(type)));
I have taken reference from here Can't enable Entity History in ASP.NET Zero
Below is entity definition
[Audited]
public partial class QuestionResponse : AuditedEntity<long>
{
public long ApplicationId { get; set; }
public long QuestionId { get; set; }
public string Response { get; set; }
public string Remark { get; set; }
public bool IsActive { get; set; }
public Application Application { get; set; }
public AbpUsers CreatorUser { get; set; }
public AbpUsers LastModifierUser { get; set; }
public Question Question { get; set; }
}
AuditedEntity<long> is not assignable to AuditedEntity.
Add a selector based on the interface IAuditedEntity instead.
Configuration.EntityHistory.Selectors.Add(
new NamedTypeSelector("Abp.AuditedEntities", type =>
// typeof(AuditedEntity).IsAssignableFrom(type)));
typeof(IAuditedEntity).IsAssignableFrom(type)));
Reference
From aspnetboilerplate/aspnetboilerplate's AuditedEntity.cs:
public abstract class AuditedEntity : AuditedEntity<int>, IEntity
{
}
public abstract class AuditedEntity<TPrimaryKey> : CreationAuditedEntity<TPrimaryKey>, IAudited
{
...
}

ASP.NET Model Relationship

I'm currently learning ASP.NET MVC and Web API.
I'm trying to create a User Model. Users can have any number of UserContacts. UserContacts reference the User it is a contact of and the User who is the contact. I have made a model called UserContact because attached to this Model is additional information.
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID"), Column(Order = 0)]
[Required]
public User User { get; set; }
public int ContactID { get; set; }
[ForeignKey("ContactID"), Column(Order = 1)]
[Required]
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
So this gives me an error referring to cascading Delete. How do I set up a relationship like this where two foreign keys point to the same Model type? I have yet to grasp Entity Framework syntax as well. If I don't have an ICollection of UserContacts in the User model, does this hinder my ability to grab the UserContacts associated with that User?
When you have a foreign key and the foreign key columns are not nullable(means,required). EF will automatically tries to enable cascading delete on the relationsip. In your case, it will try to enable Cascading delete for both the foreign key columns and both of them points to the same user table! That is the reason you are getting this error. What if you have a UserContact record with Both UserId and ContactID points to the same User record. Cascading delete is confused now :)
Also, since one user can have more than one Contacts, We need a Contacts property on the User table to represent that. This will be a collection of UserContact's. Also this user can be a a contact of many other people. So Let's create another property for that.
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<UserContact> Contacts { set; get; }
public ICollection<UserContact> ContactOf { set; get; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
public User User { get; set; }
public int ContactID { get; set; }
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
And in your DbContext class, We can configure the foreign key relation ships and tell EF to disable cascade delete using fluent configuration inside the overridden OnModelCreating method. The below code will disable cascading delete on both the the relationships. But for your error to go away. disabling on one foreign key is enough.
public class YourDbContext: DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserContact>()
.HasRequired<User>(g=>g.User)
.WithMany(g=>g.Contacts)
.HasForeignKey(g=>g.UserID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UserContact>()
.HasRequired<User>(g => g.Contact)
.WithMany(g => g.ContactOf)
.HasForeignKey(g => g.ContactID)
.WillCascadeOnDelete(false); // this one is not really needed to fix the error
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { set; get; }
public DbSet<UserContact> UserContacts { set; get; }
}
This will create the tables like you wanted with the necessary foreign keys.
There is not enough information for EF to figure out the relationships on the other side, so yes, you need collections. You can use the InverseProperty annotation to clarify (or fluent api statements):
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[InverseProperty("User")]
public Virtual ICollection<UserContact> Users{ get; set; }
[InverseProperty("Contact")]
public Virtual ICollection<UserContact> Contacts { get; set; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID"), Column(Order = 0)]
[Required]
public User User { get; set; }
public int ContactID { get; set; }
[ForeignKey("ContactID"), Column(Order = 1)]
[Required]
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
http://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in-code-first.aspx

Entity Framework multiple parent tables

I have an existing database that I am trying to access via Entity Framework 4.3. Most tables and relationships haven't been a problem, but this set of tables is causing me a few issues which I can't seem to find an answer to.
Here are the (condensed) entities:
Customer
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
private int addressSourceTypeID = 2;
[NotMapped]
public int AddressSourceTypeID {
get { return addressSourceTypeID; }
set { addressSourceTypeID = value; } }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
Contract
public class Contract
{
public int ContractID { get; set; }
public string Name { get; set; }
private int addressSourceTypeID = 4;
[NotMapped]
public int AddressSourceTypeID {
get { return addressSourceTypeID; }
set { addressSourceTypeID = value; } }
public virtual int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
//public virtual ICollection<Address> Addresses { get; set; }
}
Address
public class Address
{
[Key]
public int AddressID { get; set; }
public int AddressSourceTypeID { get; set; }
[ForeignKey("Customer")]
public int SourceKey { get; set; }
public virtual Customer Customer { get; set; }
//public virtual Contract Contract { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
What I have above is two entities Customer and Contract that both can have child Address entities. Currently the Address entity is set up to be a child of the Customer entity and this works fine as there isn't a link to Contract from Address.
I have tried adding in Contract to the Address entity as I have done with the Customer entity as you can see from the commented out code segments. Unfortunatly this doesn't work, but I'm not surprised due to the reference to Customer in the Address ForeignKey annotation. I even tried to create specific version of the Address entity (i.e. CustomerAddress), but I get an error when more than one entity is attempting to bind to the same table.
I have also tried using ModelBuilder in the EF DBContext however my knowledge here is pretty limited and I'm not sure how to do it in this case.
Overall, what I need is the following:
Customer entity to have a collection of child Addresses.
Contract entity to have a collection of child Addresses.
The link between these 'parent' tables to the Address table uses the following:
Customer: CustomerID => Address: SourceKey AND Customer: AddressSourceTypeID (always 2) => Address: AddressSourceTypeID.
Contract: ContractID => Address: SourceKey AND Contract: AddressSourceTypeID (always 4) => Address: AddressSourceTypeID.
If anyone could help me or point me in the correct direction that would be great.
Thanks very much.
You can either have EF enforce your SourceKey attribute using Table per Hierarchy Inheritance - and then you're mapping will break, or you can enforce the SourceKey in your business logic and only have EF manage the main Address class.
If you have to maintain your current DB schema, I think having your business logic enforce your SourceKey as a disriminator is your only option:
public class Address
{
public int AddressID { get; set; }
public int AddressSourceTypeID { get; set; }
public int SourceKey { get; set; }
public virtual Contract Contract { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contract
{
public Contract()
{
this.Addresses = new List<Address>();
}
public int ContractID { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Customer
{
public Customer()
{
this.Addresses = new List<Address>();
}
public int CustomerID { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
And this in your fluent mappings:
modelBuilder.Entity<Address>().HasOptional(t => t.Contract)
.WithMany(t => t.Addresses)
.HasForeignKey(d => d.SourceKey);
modelBuilder.Entity<Address>().HasOptional(t => t.Customer)
.WithMany(t => t.Addresses)
.HasForeignKey(d => d.SourceKey);
Alternatively - if you created a CustomerAddress and ContractAddress, you can using TPH inheritance enforce the SourceKey - but currently there's no way to map the Nav properties:
public abstract class Address
{
[Key]
public int AddressID { get; set; }
public int AddressSourceTypeID { get; set; }
public int SourceKey { get; set; }
}
public class CustomerAddress : Address
{
public virtual Customer Customer { get; set; }
}
public class ContractAddress : Address
{
public virtual Contract Contract { get; set; }
}
And this as your mapping:
modelBuilder.Entity<Address>()
.Map<ContractAddress>(m => m.Requires("AddressSourceTypeID").HasValue(2))
.Map<CustomerAddress>(m => m.Requires("AddressSourceTypeID").HasValue(4));
This will enforce AddressSourceTypeID as your discriminator - unfortunately the breakdown here is in mapping your nav property back to the ContractAddress and Customer Address. See this related post which had the same basic problem. Maybe this will start you in the right direction at least.

scaffolding seems not to work properly

I created a new asp.net MVC3 application (internet application), and then I added a new model with 3 classes:
public class BizCard
{
[Required]
public string BizCardID { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public List<string> PhoneNumbers { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public BizType type { get; set; }
public List<BizService> OfferedServices { get; set; }
public string Description { get; set; }
}
public class BizType
{
public int BizTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
}
public class BizService
{
public int BizServiceID { get; set; }
public List<BizType> AllowedBizTypes { get; set; }
public string Name { get; set; }
}
After that, I created a new controller, using the template "Controller with read/write actions and views using entity framework", I set the Model class to be "BizCard" and the data context class to be a new class which is called "BizDB". I was expecting to get a new class named BizDB that inherits from DbContext and includes 3 instances of DbSet:
DbSet<BizCard>, DbSet<BizType>, DbSet<BizService>.
In spite of that, I get the class with only one:
DbSet<BizCard>.
Am I missing something?
You are doing this using EF Code First approach.
1. So, you have to create a context class which should inherit DbContext containing required models as DbSet
2. Build the solution. Otherwise it will not be displayed at controller creation
Then you can create the controller using necessary model and its dbcontext.

What is the proper sequence of method calls when using a multi layered architecture?

I have built a simple survey-tool using MVC 3 with only 1 layer (MVC). I regret this now. All my database access and mapping is handled in the controllers, and some other mapping classes.
I would like to switch over to using three layers:
Presentation (MVC)
Business Logic
Data / Persistence (EF)
I am using the Entity Framework to handle everything with the database. The entity framework creates it's own domain classes. Where should the mapping between the Models that MVC uses and the models that EF creates go?
If the mapping is in the business layer, is there a need for the Models folder in the MVC project?
A survey-question consists of the Question itself, Rows and Columns. Theese are the models that i use:
public class Question {
public int Question_ID { get; set; }
public Boolean Condition_Fullfilled;
[Required(ErrorMessage = "Dette felt er påkrævet")]
public String Question_Wording { get; set; }
public String Question_Type { get; set; }
[Required(ErrorMessage = "Dette felt er påkrævet")]
public String Question_Order { get; set; }
public String Left_scale { get; set; }
public String Right_scale { get; set; }
public int Scale_Length { get; set; }
public String Left_Scale_HelpText { get; set; }
public String Right_Scale_HelpText { get; set; }
public Boolean Visible { get; set; }
public Boolean IsAnswered { get; set; }
public String Question_HelpText { get; set; }
public int Category_ID { get; set; }
}
public class MatrixColumns
{
public int Column_ID { get; set; }
public int Column_Number { get; set; }
public String Column_Description { get; set; }
public Boolean IsAnswer { get; set; }
public int? Procent { get; set; }
public bool Delete { get; set; }
public bool Visible { get; set; }
public int? Numbers { get; set; }
public String Help_Text { get; set; }
}
public class MatrixRows
{
public bool Delete { get; set; }
public bool Visible { get; set; }
public int Row_Id { get; set; }
public String Row_Number { get; set; }
public String Row_Description { get; set; }
public String Special_Row_CSS { get; set; }
public String Help_Text { get; set; }
// Dette er summen af procenterne af alle kolonner i rækken
public int RowSum { get; set; }
}
All the data for theese models is retrieved in the Controller, based upon a QuestionID, and mapped to a ViewModel that looks like this:
public class ShowMatrixQuestionViewModel : Question
{
public Dictionary<MatrixRows, List<MatrixColumns>> columnrow { get; set; }
public List<MatrixColumns> columns { get; set; }
public List<MatrixRows> rows { get; set; }
public ShowMatrixQuestionViewModel()
{
columns = new List<MatrixColumns>();
rows = new List<MatrixRows>();
columnrow = new Dictionary<MatrixRows, List<MatrixColumns>>();
}
}
So when i want to send a ShowMatrixQuestionViewModel to a View from my Controller, what is the route i should take?
This is my suggestion:
-> Controller calls a method in the business layer called
public ShowMatrixViewModel GetQuestion(int QuestionID) {}
-> GetQuestion calls the following methods in the data layer:
public Question GetQuestion(int QuestionId) {}
public MatrixRows GetRows(int QuestionId) {}
public MatrixColumns GetColumns(int id) {}
-> Entity framework returns "pure" objects, which i want to map over to the ones i posted above
-> GetQuestion calls methods to map the EF models to my own models
-> Last GetQuestion calls a method that maps the Questions, Rows and Columns:
ShowMatrixQuestionViewModel model = MapShowMatrixQuestionViewModel(Question, MatrixRows, MatrixColumns)
return model;
Is this correct?
Thanks in advance
To answer the first part of your question:
"Where should the mapping between the Models that MVC uses and the models that EF creates go?"
The answer is that the models MVC uses are the models created by the EF. Your EF tool in the ASP.NET MVC project is either Linq to SQL Classes or the ADO.NET Entity Framework Model. You should create these inside the Models folder in your project and they provide your data / persistence (EF).

Resources