* denormalized flags to FlagCount

* don't query all votes for every quote that is rendered
This commit is contained in:
tmont 2011-02-27 01:41:07 +00:00
parent 140b1d6bcc
commit 540f34da3e
6 changed files with 36 additions and 16 deletions

View File

@ -13,9 +13,10 @@
<many-to-one name="Game" column="game_id" not-null="true" foreign-key="fk_quote_game" fetch="join" /> <many-to-one name="Game" column="game_id" not-null="true" foreign-key="fk_quote_game" fetch="join" />
<!-- denormalization for performance purposes --> <!-- denormalization for performance purposes -->
<property name="Score" column="score" not-null="false" index="idx_score_upvotes" /> <property name="Score" column="score" not-null="true" index="idx_score_upvotes" />
<property name="UpVotes" column="upvotes" not-null="false" index="idx_score_upvotes" /> <property name="UpVotes" column="upvotes" not-null="true" index="idx_score_upvotes" />
<property name="DownVotes" column="downvotes" not-null="false" /> <property name="DownVotes" column="downvotes" not-null="true" />
<property name="FlagCount" column="flag_count" not-null="true" />
<set access="nosetter.camelcase" name="Categories" table="quote_category_map"> <set access="nosetter.camelcase" name="Categories" table="quote_category_map">
<key column="quote_id" /> <key column="quote_id" />

View File

@ -48,23 +48,31 @@ namespace VideoGameQuotes.Api {
} }
public virtual Quote AddFlag(string comment, QuoteFlagType type, User user) { public virtual Quote AddFlag(string comment, QuoteFlagType type, User user) {
flags.Add(new QuoteFlag { var flag = new QuoteFlag {
Comment = comment, Comment = comment,
Type = type, Type = type,
User = user, User = user,
Quote = this Quote = this
}); };
if (flags.Add(flag)) {
FlagCount++;
}
return this; return this;
} }
public virtual Quote RemoveFlag(QuoteFlag flag) { public virtual Quote RemoveFlag(QuoteFlag flag) {
flags.Remove(flag); if (flags.Remove(flag)) {
FlagCount--;
}
return this; return this;
} }
public virtual void ClearFlags() { public virtual void ClearFlags() {
flags.Clear(); flags.Clear();
FlagCount = 0;
} }
#endregion #endregion
@ -112,6 +120,7 @@ namespace VideoGameQuotes.Api {
public virtual int UpVotes { get; private set; } public virtual int UpVotes { get; private set; }
public virtual int DownVotes { get; private set; } public virtual int DownVotes { get; private set; }
public virtual int Score { get; private set; } public virtual int Score { get; private set; }
public virtual int FlagCount { get; private set; }
public virtual QuoteDto ToDto() { public virtual QuoteDto ToDto() {
return new QuoteDto { return new QuoteDto {

View File

@ -81,6 +81,8 @@ namespace VideoGameQuotes.Web.Controllers {
}; };
return Json(this.CreateJsonResponse(null, data)); return Json(this.CreateJsonResponse(null, data));
} catch (CannotVoteTwiceException) {
return Json(this.CreateJsonErrorResponse("You have already voted for this quote; you can reverse your vote by voting in the other direction"));
} catch { } catch {
return Json(this.CreateJsonErrorResponse("An error occurred while trying to process your vote")); return Json(this.CreateJsonErrorResponse("An error occurred while trying to process your vote"));
} }
@ -195,7 +197,7 @@ namespace VideoGameQuotes.Web.Controllers {
try { try {
var quote = model.QuoteId > 0 var quote = model.QuoteId > 0
? quoteService.GetQuote(model.QuoteId) ? quoteService.GetQuote(model.QuoteId)
: new Quote {Creator = currentUserProvider.CurrentUser}; : new Quote { Creator = currentUserProvider.CurrentUser };
quote.Game = quoteService.GetGame(model.GameId); quote.Game = quoteService.GetGame(model.GameId);
quote.Text = model.QuoteText; quote.Text = model.QuoteText;
@ -214,7 +216,7 @@ namespace VideoGameQuotes.Web.Controllers {
quote = quoteService.SaveQuote(quote); quote = quoteService.SaveQuote(quote);
return RedirectToAction("Quote", new {id = quote.Id, text = quote.GetUrlFriendlyText()}); return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() });
} catch (Exception e) { } catch (Exception e) {
ModelState.AddModelError("save", e.Message); ModelState.AddModelError("save", e.Message);
ResetEditQuoteModel(model); ResetEditQuoteModel(model);

View File

@ -6,15 +6,11 @@
<div class="quote-data clearfix"> <div class="quote-data clearfix">
<div class="quote-score-container"> <div class="quote-score-container">
<div class="vote-container"> <div class="vote-container">
<% if (!Model.VotedUp) { %>
<span class="vote-for" title="I like this quote">&#x25B2;</span> <span class="vote-for" title="I like this quote">&#x25B2;</span>
<% } %>
</div> </div>
<div class="quote-score" title="+<%= Model.Quote.UpVotes %>, -<%= Model.Quote.DownVotes %>"><%= Model.Quote.Score %></div> <div class="quote-score" title="+<%= Model.Quote.UpVotes %>, -<%= Model.Quote.DownVotes %>"><%= Model.Quote.Score %></div>
<div class="vote-container"> <div class="vote-container">
<% if (!Model.VotedDown) { %>
<span class="vote-against" title="I hate this quote">&#x25BC;</span> <span class="vote-against" title="I hate this quote">&#x25BC;</span>
<% } %>
</div> </div>
</div> </div>
@ -36,7 +32,7 @@
<a class="quote-permalink" href="<%= Url.Action("quote", "quote", new { id = Model.Quote.Id, text = Model.Quote.GetUrlFriendlyText() }) %>" title="permanent link to this quote"></a> <a class="quote-permalink" href="<%= Url.Action("quote", "quote", new { id = Model.Quote.Id, text = Model.Quote.GetUrlFriendlyText() }) %>" title="permanent link to this quote"></a>
<% if (Model.User != null && Model.User.Group >= UserGroup.Admin) { %> <% if (Model.User != null && Model.User.Group >= UserGroup.Admin) { %>
<a class="edit-link" href="<%= Url.Action("edit", "quote", new { id = Model.Quote.Id }) %>" title="edit this quote"></a> <a class="edit-link" href="<%= Url.Action("edit", "quote", new { id = Model.Quote.Id }) %>" title="edit this quote"></a>
<small>(<%= Model.Quote.Flags.Count() %>)</small> <small>(<%= Model.Quote.FlagCount %>)</small>
<% } %> <% } %>
</p> </p>
</div> </div>

View File

@ -151,11 +151,19 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
.AddPublisher(kaga) .AddPublisher(kaga)
.AddPublisher(sega); .AddPublisher(sega);
var zelda2 = new Game { Creator = creator, Name = "Zelda II: The Adventure of Link", Website = "http://en.wikipedia.org/wiki/Zelda_II:_The_Adventure_of_Link", Region = Region.NorthAmerica | Region.Japan | Region.PAL }
.AddSystem(nes)
.AddSystem(fds)
.AddSystem(gba)
.AddSystem(gcn)
.AddPublisher(nintendo);
using (var tx = session.BeginTransaction()) { using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Game>(session); var repo = new NHibernateRepository<Game>(session);
repo.Save(loz); repo.Save(loz);
repo.Save(crystalis); repo.Save(crystalis);
repo.Save(zeroWing); repo.Save(zeroWing);
repo.Save(zelda2);
tx.Commit(); tx.Commit();
} }
#endregion #endregion
@ -175,9 +183,12 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
var hopOnMyBack = new Quote { Creator = creator, Game = crystalis, Text = "Please hop on my back. I'll take you wherever you like." } var hopOnMyBack = new Quote { Creator = creator, Game = crystalis, Text = "Please hop on my back. I'll take you wherever you like." }
.AddCategory(dolphins); .AddCategory(dolphins);
var error = new Quote { Creator = creator, Game = zelda2, Text = "I am Error." };
using (var tx = session.BeginTransaction()) { using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Quote>(session); var repo = new NHibernateRepository<Quote>(session);
repo.Save(allYourBase); repo.Save(allYourBase);
repo.Save(error);
repo.Save(dangerousToGoAlone); repo.Save(dangerousToGoAlone);
repo.Save(hopOnMyBack); repo.Save(hopOnMyBack);
repo.Save(dodongo); repo.Save(dodongo);

View File

@ -148,9 +148,10 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD
modified DATETIME, modified DATETIME,
creator INTEGER not null, creator INTEGER not null,
game_id INTEGER not null, game_id INTEGER not null,
score INTEGER, score INTEGER not null,
upvotes INTEGER, upvotes INTEGER not null,
downvotes INTEGER, downvotes INTEGER not null,
flag_count INTEGER not null,
primary key (quote_id) primary key (quote_id)
); );