1

I am stuck in a problem where I want to show model's properties on layout page. With the reference of this answer I tried to implement the model as the following way

CompanyProfile Model

[Table("tblCompany")]
    public abstract class CompanyProfile
    {
        [Key]
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        public string CompanyLogo { get; set; }
        public string TitlePic { get; set; }
        public string CopyText { get; set; }
        public string RegText { get; set; }
    }

and

Employee model is like

[Table("tblEmployee")]
    public class Employee:CompanyProfile
    {
        [Key]
        public int EmpID { get; set; }
        public string Name { get; set; }
        public string Gender { get; set; }
        public int DepartmentId { get; set; }
        public string EmpNo { get; set; }
    }

and

Department model is like

[Table("tblDepartment")]
    public class Department:CompanyProfile
    {
        [Key]
        public int DeptID { get; set; }
        public string DeptName { get; set; }
    }

as you can see both the models are inherited from

CompanyProfile

model. Now my problem is when I am trying to access CompanyProfile model in my controller it is giving me an error

"Invalid column name 'CompanyId'.\r\nInvalid column name 'CompanyId'"

because entity framework is creating the table on behalf of model and joining these tables and tries to find

CompanyId in tblEmployee

to the best of my knowledge.

SampleContext class is like

public class SampleContext:DbContext
    {
        public DbSet<Employee> empList { get; set; }
        public DbSet<Department> deptList { get; set; }
        public DbSet<CompanyProfile> Profile { get; set; }
    }

and HomeController is like

SampleContext context=new SampleContext();
        public ActionResult Index()
        {
            CompanyProfile profile;
            if (Session["Profile"] == null)
            {
                Session["Profile"] = context.Profile.FirstOrDefault();
            }
            profile = (CompanyProfile)Session["Profile"];
            return View(profile);
        }

Here is my Layout.cshtml code

 @model ShareLayoutToContent.Models.CompanyProfile
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="shortcut icon" href="@Url.Content(Model.TitlePic)">
</head>

Now can you please provide where I am committing mistakes. Thanks in advance.

Community
  • 1
  • 1
RaviKant Hudda
  • 1,042
  • 10
  • 25
  • 1
    CompanyProfile should be a property in Employee and Department, public CompanyProfile Company { get; set; }. this is a good article http://rachelappel.com/building-a-relational-data-model-in-asp-net-mvc-3-w-ef-code-first/ – Emil Nov 07 '16 at 09:54
  • Your problem does not seem to be related to MVC, passing models to views, or to the linked question (which is about passing models to the layout page). It's purely about setting up inheritance in Entity Framework. – GSerg Nov 07 '16 at 10:01
  • I don't know if it's a good way to make an entity with `[key]` inherit from an other entity with also a `[key]`. – Stef Geysels Nov 07 '16 at 10:01
  • @DDDSoft: I know but I could not find any other proper solution to implement..:-( – RaviKant Hudda Nov 07 '16 at 10:02
  • 1
    Is it necessary to use inheritance in your case? Is the `CompanyProfile` not just a property of `Employee` and `Department` as Emil mentioned? – Stef Geysels Nov 07 '16 at 10:06
  • @DDDSoft there is no inheritance involved between CompanyProfile and other model. But when I am trying to call employee page on view page model is defined as Employee model but Layout page is already referring model is referring to CompanyProfile model so this is clashing. – RaviKant Hudda Nov 07 '16 at 10:11

1 Answers1

0

Looking at the link you provided in your question, the intention is to create a main model that will allways be the same e.g.:

public class BaseModel
{
    public CompanyProfile Profile { get; set; }
    public Employee Employee { get; set; }
    public Department Department { get; set; }
}

So your entity's would be:

[Table("tblCompany")]
public class CompanyProfile
{
    [Key]
    public int CompanyId { get; set; }
    public string CompanyName { get; set; }
    public string CompanyLogo { get; set; }
    public string TitlePic { get; set; }
    public string CopyText { get; set; }
    public string RegText { get; set; }
}

[Table("tblEmployee")]
public class Employee
{
    [Key]
    public int EmpID { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public int DepartmentId { get; set; }
    public string EmpNo { get; set; }
    public CompanyProfile profile { get; set; } //if needed
}

[Table("tblDepartment")]
public class Department
{
    [Key]
    public int DeptID { get; set; }
    public string DeptName { get; set; }
    public CompanyProfile profile { get; set; } //if needed
}

And then you'll be able to create your MainView based upon that BaseModel.

HomeController:

SampleContext context=new SampleContext();
public ActionResult Index()
{
    CompanyProfile profile;
    if (Session["Profile"] == null)
    {
       Session["Profile"] = context.Profile.FirstOrDefault();
    }
    profile = (CompanyProfile)Session["Profile"];
    return View(new BaseModel { Profile = profile });
}

View or MainLayout:

@model ShareLayoutToContent.Models.BaseModel
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="shortcut icon" href="@Url.Content(Model.Profile.TitlePic)">
</head>

The @Model will contain an object of the BaseModel so everything you put in that object would be available in the mainlayout as well as in the views. You'll just need to return always a view based upon the BaseModel. That's the reason I also declared the property's Employee and Department in the BaseModel Class.
So in every action you'll need to put:

return View(new BaseModel { /*property's you need */ });

I would rather recommend you to put the CompanyProfile in a ViewBag and forget the BaseModel Than you can keep the original viewmodels and place "almost static" values in procedures who can be called in e.g. the constructor of the Controller.

public class HomeController : Controller
{
    SampleContext context=new SampleContext();

    public HomeController()
    {
        ViewBag.CompanyProfile = context.Profile.FirstOrDefault();      
    }

    public ActionResult Index()
    {
        return View();
    }
}
Stef Geysels
  • 1,023
  • 11
  • 27
  • 1
    @RaviKant Hudda have a look at this article https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx – Emil Nov 07 '16 at 10:53
  • The issue is that a `@model` must be passed to two places (layout and view), but there is only one entry point (the `View()` call). You have to use inheritance to make it work. There are other ways to make it work (like passing data in the `ViewBag` instead), but if you want a different `@model` on both layout and view they must inherit from one another. – GSerg Nov 07 '16 at 11:04
  • @GSerg can you plz tell me if I use ViewBag or ViewData and pass the entire model (cause my actual base table is so large that I can't provide each column's reference) to ViewBag how will I retrieve that data in above given scenario. I know how to get that data in loop but if I want to get single element I couldn't do that. – RaviKant Hudda Nov 07 '16 at 11:11
  • 1
    @RaviKantHudda In the same way you use viewbag in principle. It's dynamically dispatched and the calls to properties will be resolved at runtime. You put your `Employee` in the bag, you call `ViewBag("Employee").CompanyName` in the layout. – GSerg Nov 07 '16 at 11:21
  • @DDDSoft Thanks your solution also worked for with some modifications. – RaviKant Hudda Nov 07 '16 at 11:24
  • @DDDSoft can you please tell me how to retain value of this base class across the action. Because for index page its working but for other pages it is becoming null.. – RaviKant Hudda Nov 07 '16 at 14:44
  • 1
    @RaviKantHudda I updated my answer. You'll have to put `return View(new BaseModel { /*property's you need */ });` in every action. – Stef Geysels Nov 07 '16 at 18:53
  • @DDDSoft Sir I have just last question that if my profile object is of type Task then how would I implement it in Constructor becuase constructor doesn't allow async operations. Please guide me in this way... – RaviKant Hudda Nov 08 '16 at 14:49
  • I'm sorry but I'm not familiar with async ASP. Maybe you can start a [new](http://stackoverflow.com/questions/ask) question? – Stef Geysels Nov 09 '16 at 08:23