1

I am new to ASP.NET MVC and trying to list some companies, then all contacts under that each company. I think I am getting close to make it work, so please help if you can.

The model for table and field name:

namespace ERP.Models
{
    [Table("ERP_Company")]
    public class ERP_Company
    {
        [Key]
        public int CompanyID { get; set; }
        public string Name { get; set; }
    }

    [Table("ERP_CompanyContact")]
    public class ERP_Contact
    {
        [Key]
        public int ContactID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int CompanyID { get; set; }
    }
}

These are the methods getting the Company and Contact list:

namespace ERP.Models
{
    public class Method1
    {
        public ERPEntities db = new ERPEntities();

        public List<ERP_Company> getCompanyList()
        {
            List<ERP_Company> companyList = (
                from c in db.ERP_Company
                where c.Name.Contains("Network")
                select c).Take(10).ToList();    
            return companyList;
        }

        // This below method needs to get the passing CompanyID from getCompanyList for filtering.
        public List<ERP_Contact> getContactList()
        {
            List<ERP_Contact> contactList = (
                from cc in db.ERP_CompanyContact
                select cc).Take(50).ToList();
            return contactList;
        }

        /*  Tried this below, but not work for the Controller, maybe I am doing wrong.
        public List<ERP_Contact> getContactList(int CompanyID)
        {
            List<ERP_Contact> contactList = (
                from cc in db.ERP_CompanyContact
                where cc.CompanyID == CompanyID
                select cc).Take(50).ToList();
            return contactList;
        }
         */

    }
}

Use ViewModel (suggested from other post), combine both models:

namespace ERP.Models
{
    public class ViewModelDemoVM
    {
        public List<ERP_Company> allCompanies { get; set; }
        public List<ERP_Contact> allContacts { get; set; }
    }
}

This code in the Controller:

Method1 _repository = new Method1();
public ActionResult ViewModelDemo()
        {
            ViewModelDemoVM vm = new ViewModelDemoVM();
            vm.allCompanies = _repository.getCompanyList();
            vm.allContacts = _repository.getContactList();
            return View(vm);
        }

Lastly, the view code:

@model ERP.Models.ViewModelDemoVM 

@{
    ViewBag.Title = "ViewModelDemo";
}

<h2>ViewModelDemo</h2>

<ul>
    @foreach (var company in Model.allCompanies)
    {         
        <li>@company.CompanyID | @company.Name</li>
        <ul>       
        <!-- HERE is I want to put the filtering... foreach contact WHERE CompanyID =  Model.allCompanies.CompanyID-->
        @foreach (var contact in Model.allContacts)
        {        
            <li>@contact.ContactID | @contact.FirstName</li>                             
        }
        </ul>
    }
</ul>

How can I filter the contacts (2nd loop) based on the @company.CompanyID? Sample code would be appreciated.

Thanks in advance.

3
  • 1
    Your view model should have the nested strucuture. That means, It wil have a list of companies, each company will have a list of contacts. Populate the data in your GET action and simply read and render in the view Commented Apr 10, 2018 at 22:45
  • @Shyju, sorry I'm a beginner and not able to follow your suggestions. Would be great if you can provide me a sample code. thanks for the reply. Commented Apr 10, 2018 at 23:26
  • Posted an answer for your reference, Commented Apr 11, 2018 at 0:09

2 Answers 2

2

you can apply where clause in second loop. try below code. i hope this helps

@model ERP.Models.ViewModelDemoVM 

    @{
        ViewBag.Title = "ViewModelDemo";
    }

    <h2>ViewModelDemo</h2>

    <ul>
        @foreach (var company in Model.allCompanies)
        {         
            <li>@company.CompanyID | @company.Name</li>
            <ul>       
            <!-- HERE is I want to put the filtering... foreach contact WHERE CompanyID =  Model.allCompanies.CompanyID-->
            @foreach (var contact in Model.allContacts.Where(x=>x.CompanyId ==company.CompanyID)
            {        
                <li>@contact.ContactID | @contact.FirstName</li>                             
            }
            </ul>
        }
    </ul>
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, it works perfect. Thank you so much for helping.
@Milacay glad that I'm able to help you!
2

You should create a view model with nested structure and use that. Remember, view models are specific to the view. So build it as your view needs it.

public class CompanyVm
{
    public string Name { set; get; }
    public IEnumerable<ContactVm> Contacts { set;get;}
}
public class ContactVm
{
    public string Name { set; get; }
}
public class ViewModelDemoVM 
{
    public List<CompanyVm> Companies { set; get; }
}

Your Contact table/entity already has a foriegn key/navigational property to Company entity/table. So all you have to do is, get the companies and it's corresponding customers,map it to our view model and use it in the view.

Add a collection type to Company entity class to access it's contacts.

public class ERP_Company
{
    [Key]
    public int CompanyID { get; set; }
    public string Name { get; set; }
    public ICollection<Contact> Contacts { set; get; }
}

Now in your action method, you can get the data

public IActionResult ViewModelDemo()
{
    var vm = new ViewModelDemoVM();
    vm.Companies = db.Companies
                     .Select(a => new CompanyVm { Name = a.Name,
                                                  Contacts = a.Contacts
                                                              .Select(c => new ContactVm
                                                                     { Name = c.Name })}
                      ).ToList();
    return View(vm);
}

Now in your view, just loop through the company and for each company, loop through it's contacts

@model ViewModelDemoVM 
@foreach(var company in Model.Companies)
{
    <h3>@company.Name</h3>
    <h5>Contacts</h5>
    @foreach(var contact in company.Contacts)
    {
        <p>@contact.Name</p>    
    }
}

Some notes

  1. Create view models as needed by view
  2. Do not mix entity classes (used by ORM) with view models
  3. Keep less logic/C# code in views

I used class generic class names (Contact instead ERP_Contact) and property names. When you use the above code, make the needed changes to use your existing names if needed.

6 Comments

thanks a lot for taking time posting the code, really appreciated. I am trying right now, but running into two small issues: (1) I couldn't find IActionResult for name space, can I use ActionResult instead? (2) Is there a way to filter only companies with name contains 'network' like my post (maybe from URL Query String)? I have around 15K companies and 50K contacts, I am afraid it will loop through all of them which will crash the browser if I able to get it works.
1. Yes you can replace ActionResult with IActionResult. 2. You can add a filter just before Select method call in the LINQ expression. db.Companies.Where(x=>x.Name.StartsWith("M").Select(
I am getting this error The entity types 'Contact' and 'ERP_Contact' cannot share table 'ERP_CompanyContact' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship. I just checked the Contacts table, it does have foreign key CompanyID from the Primary key of the Company table. Still figuring out... thanks again for helping. I know I am learning the correct way for ViewModel nesting.
Read the lat para of the answer. I used more generic class names. You may use your existing entity
thank you so much for helping. I finally got it working correctly now. the error above was because I copied the "public class ERP_Contact" and renamed to the Contact you used. Somehow, it doesn't like the `[key]' in both classes.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.