0

I am using Entity Framework for my latest project and my goal is to retrieve the count of the amount of likes a product in the system has.

I have 2 models:
Product and ProductLike

I would like to be able to add an int property to the Product model called NumberOfLikes. However, if I do this EF Migrations will create it as a column in the database. Is there a way to declare a property in a model and then simply get all products and join to get the product like count and set the property?

I am aware this is somewhat what ViewModels are for, but I would like to make the NumberOfLikes property part of the product well before the UI layer, just not part of the database.

Blake Rivell
  • 13,105
  • 31
  • 115
  • 231
  • Well you should be using a view model, but you can always use the [NotMappedAttribute](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.schema.notmappedattribute(v=vs.110).aspx) –  Feb 17 '16 at 04:07
  • My repository should know absolutely nothing about the ViewModel though. ViewModels stay within the UI layer (correct me if I am wrong)? So if this is the case how could the Repository layer return a List of type ProductViewModel? I am a bit concerned about my project structure now, unless simply using NotMappedAttribute is fine in my situation. – Blake Rivell Feb 17 '16 at 04:08
  • Not sure I understand your comment. Of course the repository should not know anything about view models. In you controller, you initialize the view model, map the data model values to it and then set the `NumberOfLikes` - e.g. `viewModel.NumberOfLikes = db.ProductLike.Where(...).Count();` –  Feb 17 '16 at 04:11
  • Yes what you said makes complete sense but without having the repository return a complex object of Product that includes ProductLikes and doing it a more efficient way where it returns just the ProductLikeCount. Is the only way to use a NotMappedAttribute? I would like my repository function to get all products joining with the productlike table just to get the count and then set it as Product.NumberOfLikes.. This is starting to scare me it seems like no one tampers with there model in this way at all, but still gets the information they need. – Blake Rivell Feb 17 '16 at 04:13
  • Check this if you really want a property in your entity model, but do not want to generate a table column for that. http://stackoverflow.com/questions/10385248/ignoring-a-class-property-in-entity-framework-4-1-code-first/10385738#10385738 – Shyju Feb 17 '16 at 04:14
  • Again I don't understand you last comment. There is no difference in 'efficiency' –  Feb 17 '16 at 04:16
  • @StephenMuecke please see this post: http://stackoverflow.com/questions/35424302 and the answer to it. Originally I was just going to do an Include and get the ProductLikes making Product a complex object, but lets say I don't want to do that, is there any other way to simply just get the Count of product likes only? – Blake Rivell Feb 17 '16 at 04:17
  • Exactly! That's just what I am saying. You get just the count :) –  Feb 17 '16 at 04:20
  • @StephenMuecke Ok so here is what I currently have in my repository... Should this stay as is? return _context.Products .Include(p => p.Likes) .OrderBy(t => t.CreatedDate) .ToList(); – Blake Rivell Feb 17 '16 at 04:21
  • Yes you could do that. (but are you really showing all products or just one?) And then its `List products = _context.Products .Include(p => p.Likes) .OrderBy(t => t.CreatedDate).Select(p => new ProductVM{ ID = p.ID, ......... , NumberOfLikes = p.Likes.Count() }).ToList();` –  Feb 17 '16 at 04:29
  • Or if your repository returns `List` then in the controller - `List data = yourRepositorty.FetchProducts(); List products.Select(p => new ProductVM{ ...... }).ToList();` –  Feb 17 '16 at 04:32
  • So yes in my controller I would do something like that, but isn't that what the guy in the other post is trying to get me to avoid doing? When pulling from the Database I am pulling and binding all of the properties for ProductLike when I only need the count. I guess I am so used to old school stored procs where you select what you need and your class matches the select. Or did he mean why send it all to the ViewModel.. Maybe I misunderstood. I took it as why retrieve all of the extra properties from the database. Ultimately I should just ask him, but do you agree that he meant ViewModel? – Blake Rivell Feb 17 '16 at 04:32
  • add [NotMapped] on your NumberOfLikeProperty – Mir Gulam Sarwar Feb 17 '16 at 04:41
  • @BlakeRivell, The fact that your returning all Products means that in order to get the count, you need to access all Likes. And looking at that previous question, you will also need to get likes for the current user (as a visual indicator and to know if clicking the button means 'add' or 'delete' a Like). So it really makes no difference :) –  Feb 17 '16 at 04:59
  • I got ya I'm just going to do it the way I have it, which is the way you told me to do it. Look at his new comment on my post.. he did mean database. – Blake Rivell Feb 17 '16 at 05:03
  • @BlakeRivell, Not sure which comment you mean. But there seems to be some misunderstanding in MoXplod's answer and the comments. In order to get the count of `Likes` for each `Product`, you still need to read every row of the `Likes` table in the database. –  Feb 17 '16 at 05:30
  • Yes, that is correct, but not necessarily bind all of the properties of the Likes from the database. Make sense or no? This is what he said: I meant you should not get all the rows of ThumbsUps table(ICollection in your Product table) from the database itself. Just the count of ThumbsUps per Product as that is all you need. – Blake Rivell Feb 17 '16 at 05:37
  • Well sort of (you only need the count) - But in order to get the count, its still necessary to read every row in the table. –  Feb 17 '16 at 05:57
  • Thanks for the help stephen! – Blake Rivell Feb 17 '16 at 06:15

1 Answers1

1

Try this creating a partial class of the class used in generating your entities and adding the NumberOfLikes property.

public partial class Product
{
  public int NumberOfLikes{get; set;}
}

Ensure this class is in the same namespace with your product model class used in generating your database.

With this after loading other properties of your product model, you can populate the NumberOfLikes property and display it.

If you wish to set the value of the NumberOfLikes property everytime you have your product model object, you can do some like this as follows:

public partial class Product
{ 
  int _numberOfLikes;

  public int NumberOfLikes{


  get{ 

   return _numberOfLikes;

     }


   set{
        _numberOfLikes = this.xxxxx ( the this keyword gives you access to all properties your earlier product model has )

      }

}

Note: Setting the NumberOfLikes value from your new partial class might affect performance.

Ziregbe Otee
  • 534
  • 3
  • 9
  • I actually can't believe I forgot about this technique. I used to use it when I used EF DB First to add custom properties that a query or a stored proc returned that had nothing to do with the actual database model! Thanks! – Blake Rivell Feb 17 '16 at 13:38