2

I have a Product table with columns "ProductId(pk), P_Name, Price, Quantity"

and another table VoteLogs with columns "V_id(pk), ProductId, UserId, Vote"

I've implemented the rating feature by following this tutorial

The Vote Log table contains the following data

VoteLog Table Data

As you can see customer1@gmail.com and customer2@gmail.com both voted product 28 but customer2@gmail.com has also voted product 20, 72, 1187, and 1188

Now when customer1@gmail.com log in, I want to display him product 20, 72, 1187, 1188 because customer1 and customer2 both voted the same product so they might have similar taste.

I have tried and came this far,

public ActionResult BasedOnRating()
    {
        string UserId = User.Identity.GetUserName(); //logged in with customer1@gmail.com
        var query = from vv in db.VoteLogs
                    join pp in db.Products
                    on vv.ProductId equals pp.ProductId
                    where !(db.VoteLogs.Where(c => c.UserName == UserId)
                           .Select(c => c.Product.ProductId).ToList())
                           .Contains(vv.Product.ProductId) && (vv.UserName == "customer2@gmail.com")
                    select pp;

        return View(query);
    }

and I get the desired result:

Result of query

But I don't want to write customer2@gmail.com in the query, What If i have 1000+ users. I guess here I should pass the list of users who has voted the same products. I'm confused here. I would appreciate any help. Thanks

user3223395667
  • 239
  • 1
  • 6
  • 16
  • What is the purpose of the `Votes` column of `Product` table? (there seems no need for that when you have a `Votes` table). Are you wanting to display all products that a use has not voted on, or all products that a user has not voted on but that has received votes from another user? Its not clear what your logic is. –  Dec 06 '15 at 21:05
  • @StephenMuecke `Votes` column in `Product` table has this type of value `0,0,0,0,0` = `1,2,3,4,5`. If user voted 5 then it will be `0,0,0,0,1`, if another user voted 5 the same product then `0,0,0,0,2`. I have followed this tutorial (http://www.dotnetfunda.com/articles/show/2828/developing-a-star-rating-in-aspnet-mvc) – user3223395667 Dec 07 '15 at 07:51
  • @StephenMuecke and I want to display products that user has not voted but another users has voted. For example If you have voted `ProductA` and I have voted `ProductA` and `ProductB` then I want to display `ProductB` to you, because we have voted similar `ProductA` which means we might have similar choice. – user3223395667 Dec 07 '15 at 07:55
  • `db.VoteLogs.Where(v => v.UserId != user).Select(v => v.P_id).Distinct();` will give you _products that user has not voted but another users has vote_ but I'm not sure that's what you really want. –  Dec 07 '15 at 10:01
  • @StephenMuecke Please read my post and comments, I've explain what I want. If 2 Users has voted the same product then display products that User1 has not voted but User2 has voted. Same goes for User2, displayproducts to User2 that User1 has voted since they both voted the same product before – user3223395667 Dec 07 '15 at 11:59
  • @StephenMuecke Please see my updated question. – user3223395667 Dec 09 '15 at 08:12
  • Much clearer :) No time to test now, but to break it down, I think (1) you need to get the ID's of all the products the current user voted - `query1 = select productID where UserName = currentUser` (2) get all users who voted on those products (except current user) `query2 = select distinct UserName where ProductID in query1` and (3) get all the products where UserName in query2. But that suggests multiple `.Contains()` which is not efficient and a Stored Procedure might be better. And if you have 1000+ users and products, you query might also return 1000+ rows. –  Dec 09 '15 at 08:42
  • @StephenMuecke yeah I think so, I tried alot and get this far. I'll try your way, If you can write an example with `.Contains()` or stored procedure – user3223395667 Dec 09 '15 at 08:52
  • It will have to wait until tomorrow :) –  Dec 09 '15 at 08:54

3 Answers3

1

Please refer below code.

you can change the userId and verify the output.

    public class Products
    {
        public int pdid { get; set; }
        public string pdname { get; set; }
    }
   public class Votes
    {
        public int pdid { get; set; }
        public string cust { get; set; }
        public int vt { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Products> pd = new List<Products>()
            {
                new Products{pdid=1, pdname="abc"},
                new Products{pdid=2, pdname="ghi"},
                new Products{pdid=3, pdname="mnp"},
                new Products{pdid=4, pdname="pqr"},
                new Products{pdid=5, pdname="xyz"}

            };

            List<Votes> vt = new List<Votes>()
            {
                new Votes{pdid=1,cust="c1",vt=2},
                new Votes{pdid=2,cust="c1",vt=2},

                new Votes{pdid=1,cust="c2",vt=2},
                new Votes{pdid=3,cust="c2",vt=2},
                new Votes{pdid=4,cust="c2",vt=2},

                new Votes{pdid=2,cust="c3",vt=2},
                new Votes{pdid=5,cust="c3",vt=2}
            };

            var UserId = "c3";

            var query = (from vv in vt
                         join pp in pd
                             on vv.pdid equals pp.pdid
                         join vvv in vt
                             on vv.pdid equals vvv.pdid
                         where !(vt.Where(c => c.cust == UserId)
                             .Select(c => c.pdid).ToList())
                             .Contains(vv.pdid) && (vv.cust == vvv.cust)
                         select new
                         {
                             pdid = vv.pdid,
                             pdname = pp.pdname
                         }).Distinct();

            foreach (var p in query)
            {
                Console.WriteLine(p.pdid + "-" + p.pdname);
            }

            Console.ReadLine();
        }
    }
Sahi
  • 1,454
  • 1
  • 13
  • 32
  • I'm getting this error with your query.`The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery`1[<>f__AnonymousType10`1[System.Nullable`1[System.Int32]]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[FypStore.Models.Product]'.` – user3223395667 Dec 09 '15 at 10:25
  • Please refer this:- http://stackoverflow.com/questions/21110590/the-model-item-passed-into-the-dictionary-is-of-type-system-data-entity-infrast – Sahi Dec 09 '15 at 10:32
  • `select new { pdid = vv.Product.ProductId, pdname = pp.Name }).Distinct(); foreach (var item in qq) //retrieve each item and assign to model { listProduct.Add(new Product() { Name = item.pdname, ProductId = item.pdid }); } return View(listProduct); ` I did it like this but not getting the desired result – user3223395667 Dec 09 '15 at 10:54
  • Please check below answer. – Sahi Dec 10 '15 at 11:51
1

To break this down into its individual components

First you need to get the ID's of the products the current user has voted on

string UserId = User.Identity.GetUserName();
var userProducts = db.VoteLogs.Where(v => v.UserName == userId).Select(v => v.ProductId);

Then get all the other users who have also voted for one of those products

var likeUsers = db.VoteLogs.Where(v => userProducts.Contains(v.ProductId) && v.UserName != userId).Select(v => v.UserName);

Then get all other products that those users have voted on

var likeProducts = db.VoteLogs.Where(v => likeUsers.Contains(v.UserName)).Select(v => v.ProductId).Except(userProducts);

And finally return those products

return View(db.Products.Where(p => likeProducts.Contains(p.ID)));

Based on the table you have shown, this will return products 20, 72, 1187 and 1188. If you were to add another row to your votes table with ProductId = 109 and UserName = "customer1@gmail.com" then the results will be 19, 20, 30, 72, 1111, 1187 and 1188.

Note that since you have potentially thousands of users and products, this could return thousands of products to the view, so you may want to consider limiting the results, for example you might order the likeProducts query by Vote (highest) and take only the top #.

  • Thanks man! That worked :) Yeah I will and also I will use `.Take()`. Again Thanks :) – user3223395667 Dec 10 '15 at 05:41
  • Note I just did a test with the only data you showed. You may also need to use `Distinct()` for the `likeUsers` and/or `likeProducts` queries if your getting any duplicates. –  Dec 10 '15 at 05:44
  • Yes. I already did that. Can you give me any suggestion about how can I display this on ProductDetails View Page. I know I could create a partial page and display it in other View Page. I want ot display it like this in `
    User who voted this product also voted (here goes the partial page)
    `
    – user3223395667 Dec 10 '15 at 06:01
  • or should I show it like this `Recommended Products based on your rated` or `You might also like` – user3223395667 Dec 10 '15 at 06:05
  • 1
    I would create a separate ActionResult method (with a parameter `int ID` for the productID) that returns the partial view (including your `
    .....
    ` and then in the products details page, use `@{ Html.RenderAction(action, controller, new { id = yourProductID }); }`
    –  Dec 10 '15 at 06:08
  • 1
    But based on the fact you now displaying this for just a specific product, the `var userProducts = db.VoteLogs.Where(v => v.UserName == userId).Select(v => v.ProductId);` may no longer be appropriate since its for one applicable to one product - you probably just need to check if the current users has cast a vote for that product and only run the rest of the queries if true. –  Dec 10 '15 at 06:12
  • Yeah. I'll definitely try this. Thanks again for your help! :) – user3223395667 Dec 10 '15 at 06:34
1

you can use same result set. no need of converting to list again.

Linq query is given below:

    var query = (from vv in vt
                         join pp in pd
                             on vv.pdid equals pp.pdid
                         join vvv in vt
                             on vv.pdid equals vvv.pdid
                         where !(vt.Where(c => c.cust == UserId)
                             .Select(c => c.pdid).ToList())
                             .Contains(vv.pdid) && (vv.cust == vvv.cust)
                         select new
                         {
                             pdid = vv.pdid,
                             pdname = pp.pdname
                         }).Distinct().ToList();

Added ToList().

you can pass query in your view.

Sahi
  • 1,454
  • 1
  • 13
  • 32