1

I have problem with how to and where to add if condition in view which has two models in a single view.

This is view

@foreach (service_provider SP in ViewBag.service_provider) {
    <tr>
        <td>@SP.Sp_email</td>
        <td>@SP.Sp_name</td>
        <td>@SP.city.Cityname</td>
    </tr>}@foreach (picture img in ViewBag.pictures){
    <tr> 
        <td><img src="data:image/png;base64,@Convert.ToBase64String(img.pic,0,img.pic.Length)" width="100" />
        </td>
    </tr>
}

This is picture model

public int PIC_ID { get; set; }
public string pic_name { get; set; }
public Nullable<int> belong_id { get; set; }
public byte[] pic { get; set; }

This is service_provider model

public int SPID { get; set; }
public string Sp_email { get; set; }
public string Sp_password { get; set; }
public string Sp_name { get; set; }

This is my controller

public ActionResult Index(){   
    ViewBag.service_provider = dc.service_provider;
    ViewBag.pictures = dc.pictures;
    return View();
}

The purpose of the above view is to display details of the service_provider with it's picture by where belong_id in picture equals SPID in service_provider. but I couldn't understand where do I add if condition.I'm using Database first approach

Oshink
  • 50
  • 10
  • You should create a viewmodel that encapsulates the service provider with property for its picture(s). – Crowcoder Apr 26 '16 at 19:13
  • Why don't you make one model to inherit from the other model? – Auguste Apr 26 '16 at 19:13
  • On a completely unrelated note, it is usually bad practice to store files in the database that you want to display again from a web page. This generates a lot of network IO between client and server as well as database IO. Mostly because the client will not be caching results and the web server cant efficiently return the files either. Better approaches include keeping the file on disk where it is still accessible from the client with the database containing the file path or writing a file handler in your site based on a static url per image so the web client can still cache. – Igor Apr 26 '16 at 19:35

2 Answers2

4

It would be much easier if you used a strongly typed model instead of the ViewBag. You can then add logic to your model or your controller. I personally it easier read and test. It also prevents syntax errors.

Models.cs

public class Picture {
    public int PIC_ID { get; set; }
    public string pic_name { get; set; }
    public Nullable<int> belong_id { get; set; }
    public byte[] pic { get; set; }

    // added - your FK pointing back to the corresponding service_provider
    public int SPID { get; set; }
    // added - the corresponding service_provider
    public service_provider ServiceProvider { get; set; }
}

public class service_provider {
    public int SPID { get; set; }
    public string Sp_email { get; set; }
    public string Sp_password { get; set; }
    public string Sp_name { get; set; }

    // added
    public ICollection<Picture> Pictures {get;set;}
}

Controller.cs

public ActionResult Index(){   
    var service_provider = dc.service_provider.Inculde(x => x.Pictures);
    // var pictures = dc.pictures;

    // code to add the pictures to the correct service_provider instance
    // ideally this should already be reflected in your model. 
    // If you are using EF you should be modeling this using proper data relations
    // that would allow you to execute an .Include statement on the retrieval
    // and pass the model directly into the View without the need for an additional call to pictures as the service_provider would then already contain the relations
    return View(service_provider);
}

View.cshtml

@model IEnumerable<service_provider>
@*This following line indicates that it is a list of service_provider hense the IEnumerable*@
@foreach (service_provider SP in Model){
    <tr>
        <td>@SP.Sp_email</td>
        <td>@SP.Sp_name</td>
        <td>@SP.city.Cityname</td>
    </tr>
    @*Iterate over the pictures on each model. 
    You can still split this if you want all service providers and then all pictures.*@
    @foreach (picture img in SP.Pictures){ @*changed to still look at the model*@
        <tr><td><img src="data:image/png;base64,@Convert.ToBase64String(img.pic,0,img.pic.Length)" width="100" /></td></tr>
    }
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • I'm following database first approach. can I apply Viewmodel for it? – Oshink Apr 26 '16 at 19:26
  • @Oshink - These are 2 different concepts. database first is for Entity Framework, ViewModel is for MVC. But yes you can create a model in Entity Framework (using code first or database first either way) and then pass that model to a strongly typed view in your MVC code. – Igor Apr 26 '16 at 19:27
  • 1
    This is pretty close, however, you should just be able to have this as your controller: `var service_provider=dc.service_provider.Include(sp=>sp.Pictures); return View(service_provider);`. Of course, this assumes that you either had a foreign key constraint when you created your models in which case the Pictures navigation property would have been automatically created for you, or if not, then you manually add the Navigation property yourself. – Robert McKee Apr 26 '16 at 19:27
  • @RobertMcKee - I did not initially put it in there because I did not want to put too many assumptions in the answer but had added it to the explanation in the code comments in that method. However you also writing this makes me think you are right and I should not have held it back. I updated the code. Thanks. – Igor Apr 26 '16 at 19:31
  • 1
    @Igor Fair enough Igor. It wasn't a large enough difference to start my own answer when yours was so close to the one I would have given myself. I tend to try and offer the "easy way" when people start by asking beginner questions with the assumption that perhaps they don't know the easy way either. Still, was (and is still) a good answer. – Robert McKee Apr 26 '16 at 19:40
  • @Igor I have already created classes for service_provider and picture. How do I connect them with VIew model? – Oshink Apr 26 '16 at 19:44
  • @Oshink - They are already related in the code above (see answer). You need to add an `ICollection` to your `service_provider` and make sure it is mapped correctly in your database first EF model. Once that is done you should be able to use the above posted code in the answer. – Igor Apr 26 '16 at 19:47
  • @RobertMcKee I want to join picture table with service_provider table with out adding foreign key. because there is one to many relationship between service_provider and picture. therefore I have add another table foe store data. – Oshink Apr 26 '16 at 19:48
  • @Oshink - If it is a one to many relationship then there is no 3rd table. The table on the side of the many contains a FK that points back to the table of 1. Concrete example - your `picture` table will have a FK pointing back to the `service_provider`. – Igor Apr 26 '16 at 19:49
  • @Oshink - see the update on class `Picture` which illustrates my last comment. – Igor Apr 26 '16 at 19:51
  • @Igor I'm following db first and there is ADO.net data model and there is a calls for service_provider. how do I connect View model with that class? – Oshink Apr 26 '16 at 19:53
  • @Igor I have not only service_providers pictures in pictures table. there is another table like service_provider – Oshink Apr 26 '16 at 19:57
  • @Oshink - 1. you need to model the FK in your model, see this [previous SO answer](http://stackoverflow.com/a/19591602/1260204). 2 - FKs can be nullable if there is no relationship but I have no idea how you are modeling your relationship now in your database. If that is still an open question then please start a new question about how to model your particular relationship in your database and EF leave MVC completely out of the question. Include your database schema and your corresponding EF model in your question along with any other specifics. – Igor Apr 26 '16 at 20:00
  • @Oshink Assuming your other table is people (just using that as an example since you didn't mention what your other table was), if you have a service_provider with SPID of 1, and a person with a PERSONID of 1, and a record in Pictures with belongs_to of 1, which is it a picture of? – Robert McKee Apr 26 '16 at 20:43
  • @Oshink Regardless of your database design decisions, you can follow this https://msdn.microsoft.com/en-us/data/jj713564.aspx to create a navigation property on service_provider and pictures without a foreign key constraint and then the above just all works. – Robert McKee Apr 26 '16 at 20:46
  • 1
    Although, I suggest you rethink your database design if it isn't too late. If you have multiple tables all looking at pictures, and service_providers to pictures is a 1 to many relationship, you should consider a cross reference table like ServiceProviderPictures(ServiceProviderId,PictureId) and the appropriate FKs. Then just tell EF to refresh your models and it will automatically work as well. – Robert McKee Apr 26 '16 at 20:51
0

Try:

@foreach (picture img in ViewBag.pictures)
{
     if(img.PIC_ID == ViewBag.service_provider.SPID)
{
<tr><td><img src="data:image/png;base64,@Convert.ToBase64String(img.pic,0,img.pic.Length)" width="100" /></td></tr>
}
}

BTW - Maybe better way - is check in server side and return ONLY pics that you need??

David
  • 235
  • 2
  • 18