简体   繁体   中英

avoid redundant conditional statements

Using the following code, assume I have 5 different types that I might receive in the variable type. Instead of writing 5 conditional statements, is there a way to write one and use the variable "type" to dictate what the model is, in this case "CommentVote?" Or is this more a deficiency in the way I've designed the data model with each of those 5 things having a "vote" model?

 if (type == "comment")
 {
      CommentVote voteObj = db.CommentVotes
           .Where(x => x.UserID == UserID && x.CommentID == id)
           .SingleOrDefault();
      if (voteObj != null)
      {
          voteObj.Vote = vote;
          db.SaveChanges();
      }
      else
      {
          CommentVote c = new CommentVote { 
               CommentID = id, UserID = UserID, Vote = vote, DateCreated = DateTime.Now 
          };
          db.CommentVotes.Add(c);
          db.SaveChanges();
      }

      count = (db.CommentVotes.Count(x => x.CommentID == id && x.Vote == true) - db.CommentVotes.Count(x => x.CommentID == id && x.Vote == false));
 }

Magic Code: The stuff I would love to be able to do.

 var modelName = "";
 var modelOtherName = "";
 if (type == "comment") {
      modelName = CommentVote;
      modelOtherName = CommentVotes;
 }

      modelName voteObj = db.modelOtherName
           .Where(x => x.UserID == UserID && x.CommentID == id)
           .SingleOrDefault();

Update : I'm beginning to think my model may be crap based on some of the reading referenced bellow. So I am including some of that as a reference. Let me know if that's the problem I should be trying to solve.

 public class CommentVote
 {
    public int CommentVoteID { get; set; }
    public bool Vote { get; set; }
    public DateTime DateCreated { get; set; }
    public int UserID { get; set; }
    public virtual User User { get; set; } 

    public int CommentID { get; set; }  //This row changes from model to model
    public virtual Comment Comment { get; set; }  //This row changes from model to model
 }

I have a handful of models that are almost identical.

As I understand you question, it more database architecture-related.

If those kind of votes are not very different from each other (in terms of properties) I woldn't use different tables for them. Instead create one Vote table with Type column and (as in the example you provided) nullable column for CommentID.

Then you can use class inheritance to reflect your votes (Vote base class and CommentedVote child class).

Table Per Hierarchy Inheritance in Entity Framework

Update: Best is not to repeat the same propertieses in all classes. You just use inharitence like this:

 public abstract class Vote
 {
    public int VoteID { get; set; }
    public bool isVote { get; set; }
    public DateTime DateCreated { get; set; }
    public int UserID { get; set; }
    public virtual User User { get; set; } 

    public int VoteType { get; set;} //this property specifies type of vote (e.g. VoteType=1 for CommentedVote )
 } 
 public class CommentVote : Vote
 {
    public int CommentID { get; set; }  
    public virtual Comment Comment { get; set; }  
 }
 public class OtherVote : Vote
 {
    public int OtherID { get; set; }  
    public virtual Other Other { get; set; }  
 }

In this very good blog post you can find all possible approches. The one I'm writing about is called Table per Hierarchy (TPH).

You can absolutely reduce the code to a single statement assuming that you perform the same actions and set the same data. In this case, you should have an interface that contains the common actions and data and an object factory to instantiate the correct object based on the type.

You could do it if you implement the Factory pattern with reflection, a very basic example is shown here .

In a nutshell what you do is this: Since you have 5 different types that it could be, you would make 5 different classes that each implement a specific interface. You then create the factory class to use reflection to grab the class that is the most appropriate for your situation (be it with a straight-up class name, like in the example, or with an Attribute over the class, such as here ). The factory returns an instance of that interface, which you would then just invoke the exposed method from the interface to do all of this for you.

The best part of this is that if you ever need to make another type, all you'd have to do is add another class with that attribute/name that you would be searching for in the factory. None of your other code would need to be affected, thus making you compliant with the Open/Closed Principle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM