In ASP.NET MVC how to use another model as property - c#

So I have two model, one is Company, one is Province.
[Table("Company")]
public class Company {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public int ProvinceID { get; set; }
public ProvinceModel Province{
get {
// ????
}
}
}
public class CompanyContext : MyXsiteContext {
public DbSet<Company> Companies { get; set; }
}
Here is my Province:
[Table("Province")]
public class ProvinceModel {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
}
public class ProvinceContext : MyXsiteContext {
public DbSet<ProvinceModel> Provinces { get; set; }
}
How do I get my Company, which only save the ProvinceID, to reference the Province object so I can refer to the province.name in my view?

It seems like you want to do it similar to how the navigation properties are described here.
So in the link they describe Course -> Department but for you it is Company -> Province.
Also, as an aside, if you are going to reference Province.Name in your view you might run into a Select N+1 problem so that might be something to account for (depending on your specific use case, which I'm not 100% across, just highlighting it as a potential "thing")

Related

Using Data annotations to create navigation property from class to itself?

Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.

What is the best strategy of creating code first database with inherited entities?

For example if I have a model:
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
}
public class PaymentPolicy : BasePolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy : BasePolicy {
public int ReturnTerm { get; set; }
}
... and want to create codefirst database and a repository with next requirements:
ability to retrieve base entities by Id in base type (BasePolicy). This is necessary for admin index page which displays list of policies only by it's name.
I need to have access to children specific properties (PaymentMethod if it is PaymentPolicy - etc.) using select by Id . This is necessary for edit actions.
What is the best way to do that? Should I create seperate table for each child type?
public class Database : DbContext
{
public DbSet<PaymentPolicy> PaymentPolicies { get; set; }
public DbSet<ReturnPolicy> ReturnPolicies { get; set; }
}
+ data is logically sorted
- I will not be able to get BasePolicy entity by it's unique id without joining those tables and specifying policy type in select query. That's why I should inject some PolicyType enum to base type and implement repository method which will get BasePolicy by it's type (to determine which table to get from) and only then by unique Id - and downcast BasePolicy to specific child type policy. This is the solution I'm using just now.
... should I remove inheritance at all?
public class PaymentPolicy {
public int Id { get; set; }
public string Name { get; set; }
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int Id { get; set; }
public string Name { get; set; }
public int ReturnTerm { get; set; }
}
+ data is still logically sorted
- I still will not be able to get BasePolicy entity by it's unique id.
... should I add child types as navigation properties to base type?
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
public PaymentPolicy PaymentPolicy { get; set; }
public ReturnPolicy ReturnPolicy { get; set; }
}
public class PaymentPolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int ReturnTerm { get; set; }
}
- This will destroy logic model structure
+ I will be able to get list of policies without redundant joins
+ It will provide strong one to one relationship
Or are there some more advanced strategies and techniques?

Display all blog articles of a specific user

The scenario: I have two tables: UserProfiles and BlogArticles. The blog article is inside UserProfile, so if I would like to get all blog articles of a specific user, I would type something like:
db.UserProfiles.SingleOrDefault(x=> x.UserName == User.Idenity.Name).BlogArticles
However, I would like to do this using the BlogArticles table, that is, I would like to get BlogArticles that come from the same UserProfile, as following:
db.BlogArticles(x=> ...) // these should be from one user only.
Solution1
One way is to do it backwards, as following:
db.UserProfiles.FirstOrDefault(d => d.BlogArticles.FirstOrDefault(x=> x.Id==BlogArticles) != null);
So, given a BlogArticle id, the UserProfile can be found.
However, how would I be able to get a list of articles that come from a particular userprofile using the BlogArticle table?
I've tried
db.BlogArticles.Where(x=> Functions.GetAuthor(x.Id) == User.Identity.Name).ToList()
but I get the following error:
An exception of type 'System.NotSupportedException' occurred in System.Data.Entity.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.String GetAuthor(Int32)' method, and this method cannot be translated into a store expression.
How can I solve this in a better way?
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<BlogArtilce> BlogArticles { get; set; }
public virtual ICollection<Group> Groups { get; set; }
//public DateTime Created = DateTime.Today;
}
[Table("BlogArticle")]
public class BlogArticle
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual string Name { get; set; }
public string Description { get; set; }
public virtual string Contents { get; set; }
public virtual int Views { get; set; }
public virtual string Password { get; set; }
public virtual string Tags { get; set; }
}
public class Group
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; } // this must be an int.
public string Name { get; set; }
public virtual ICollection<BlogArticle> BlogArticles { get; set; }
}
You're making this much more complicated than it needs to be. From your OP you already selected an author and should therefore have access to the author's id and the means to store it.
So, your code could look something like this, assuming that BlogArticles has a property named AuthorId:
int localAuthorId = ???; // assign from wherever you fetched it
// simpler filter:
db.BlogArticles.Where(x => x.AuthorId = localAuthorId).ToList()

Entity Framework 6 multiple table to one foreign key relationship code first

I am wondering if anyone could advise me on how to accomplish the below using code first in EF6
If I add the Table_3 as a List on to Table_1 & Table_2 in my entities. EF automatically generates a foreign key column for both tables in Table_3 instead of recognizing that they are of the same type.
My model classes are set as follows.
public interface IParent
{
int ID { get; set; }
List<Table_3> Children { get; set; }
}
public class Table_1 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_2 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual IParent Parent { get; set; }
}
EF code first generates the below
Edit
Just to let anyone having the same problems know
I have now resolved this by changing the IParent interface to an abstract class
my classes now look like the following
[Table("ParentBase")]
public abstract class ParentBase
{
[Key]
public int ID { get; set; }
public List<Table_3> Children { get; set; }
}
[Table("Table_1")]
public class Table_1 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_2")]
public class Table_2 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_3")]
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual ParentBase Parent { get; set; }
}
with a table arrangement of
this will work although it would have been nicer if the original could have been met.
I had this problem too, and I used abstract class instead of interface from the beginning.
The problem for mine was my table_3 have two navigation properties:
one is public virtual Table_1, another is public virtual Table_2, and then EF just provisioned these extra foreign key columns,
I merged the two navigation properties into one to
public virtual parentbase {get;set;}. And then it worked. Hope this helps.
Side Note,Would suggest to add virtual keyword on public List Children { get; set; } in parentbase class, because in your previous example , it was already like that.
Thanks for posting this, i came across this issue too.
You can also do like the following where you make a 1 to many relationship between Table_1 and Table_2 with Table_3 respectively:
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
Let me know if anymore clarification is required.

Three models in to one maintenance form

I want to build the one maintenance form for the following three models -
namespace mysite.Models
{
public class LevelOne
{
public int LevelOneId { get; set; }
public string Name { get; set; }
public virtual ICollection<LevelTwo> LevelTwos { get; set; }
}
}
namespace mysite.Models
{
public class LevelTwo
{
public int LevelTwoId { get; set; }
public string Name { get; set; }
public int LevelOneId { get; set; }
public virtual LevelOne LevelOne { get; set; }
public virtual ICollection<LevelThree> LevelThrees { get; set; }
}
}
namespace mysite.Models
{
public class LevelThree
{
public int LevelThreeId { get; set; }
public string Name { get; set; }
public int LevelTwoId { get; set; }
public virtual LevelTwo LevelTwo { get; set; }
}
}
The relationship is :-
LevelOne can have multiple LevelTwo's.
LevelTwo's will have a LevelOne and multiple LevelThree's.
LevelThree will have a LevelTwo.
I have cascading ddl's to select based on the relationship above.
What would be the best way to implement a maintenance form so i can add/edit/delete a level based on what is chosen in the ddl's?
Is it a case of a lot of divs being hidden and shown in javascript based on the ddl's or can something simpler be done using viewmodels or some fancy nancy .net extensions etc?
My mind hurts thinking about it :(
This could also be seen as just 1 model with 3 entities.
Level1 -> Level2 is a one to many relationship. Level2 -> Level3 is a
one to many relationship.
EF supports this. And as i clearly see from ur namespace for all
the 3 models is the same mysite.Models, i guess u already have all of
them in the same model file for EF to create the relationships.

Categories