Permalink
Browse files

Chapter 8

  • Loading branch information...
jchadwick committed Nov 4, 2012
2 parents d6a3b9f + 9660750 commit 491b7471e08bd3d732549a48288660b7a0f4adcb
@@ -13,5 +13,13 @@ public EbuyDataContext()
Database.SetInitializer(initializer);
#endif
}
+
+ protected override void OnModelCreating(DbModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity<Bid>()
+ .HasRequired(x => x.Auction)
+ .WithMany()
+ .WillCascadeOnDelete(false);
+ }
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Diagnostics.Contracts;
using System.Linq;
@@ -9,16 +10,10 @@ namespace Ebuy.DataAccess
{
public class Repository : IRepository
{
- private readonly EbuyDataContext _context;
+ private readonly DbContext _context;
private readonly bool _isSharedContext;
-
- public Repository()
- : this(new EbuyDataContext(), false)
- {
- }
-
- public Repository(EbuyDataContext context, bool isSharedContext = true)
+ public Repository(DbContext context, bool isSharedContext = true)
{
Contract.Requires(context != null);
@@ -41,6 +41,7 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
+ <Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -50,9 +51,17 @@
<ItemGroup>
<Compile Include="DataAccess\IRepository.cs" />
<Compile Include="DataAccess\Repository.cs" />
+ <Compile Include="Entities\Annotations\UniqueAttribute.cs" />
<Compile Include="Entities\Auction.cs" />
<Compile Include="DataAccess\EbuyDataContext.cs" />
+ <Compile Include="Entities\Bid.cs" />
+ <Compile Include="Entities\Category.cs" />
+ <Compile Include="Entities\Currency.cs" />
<Compile Include="Entities\Entity.cs" />
+ <Compile Include="Entities\EntityKeyGenerationException.cs" />
+ <Compile Include="Entities\Payment.cs" />
+ <Compile Include="Entities\User.cs" />
+ <Compile Include="Entities\WebsiteImage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data.Entity;
+using System.Linq;
+using System.Reflection;
+
+namespace Ebuy.DataAnnotations
+{
+ public class UniqueConstraintApplier
+ {
+ private const string UniqueConstraintQuery = "ALTER TABLE [{0}] ADD CONSTRAINT [{0}_{1}_unique] UNIQUE ([{1}])";
+
+ public void ApplyUniqueConstraints(DbContext context)
+ {
+ var modelTypes =
+ from dbContextProperties in context.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ let propertyTypeGenericArguments = dbContextProperties.PropertyType.GetGenericArguments()
+ where propertyTypeGenericArguments.Count() == 1
+ select propertyTypeGenericArguments.Single();
+
+ var modelsWithUniqueProperties =
+ from modelType in modelTypes
+ from property in modelType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ from uniqueAttribute in property.GetCustomAttributes(true).OfType<UniqueAttribute>()
+ let propertyName = property.Name
+
+ group propertyName by modelType into uniquePropertiesByModel
+
+ select new {
+ Model = uniquePropertiesByModel.Key,
+ Properties = (IEnumerable<string>) uniquePropertiesByModel
+ };
+
+ foreach (var model in modelsWithUniqueProperties)
+ {
+ foreach (var property in model.Properties)
+ {
+ string tableName = GetTableName(model.Model);
+ string query = string.Format(UniqueConstraintQuery, tableName, property);
+ context.Database.ExecuteSqlCommand(query);
+ }
+ }
+ }
+
+ private string GetTableName(Type model)
+ {
+ var modelName = model.Name;
+
+ if (modelName.EndsWith("y"))
+ modelName = modelName.Substring(0, modelName.Length - 1) + "ie";
+
+ return modelName + "s";
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class UniqueAttribute : RequiredAttribute
+ {
+ }
+}
@@ -1,26 +1,148 @@
-using System;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Diagnostics.Contracts;
+using System.Linq;
namespace Ebuy
{
- public class Auction : IEntity
+ [MetadataType(typeof(Auction.Metadata))]
+ public class Auction : Entity<Guid>
{
- public long Id { get; set; }
+ public virtual string Title { get; set; }
+ public virtual string Description { get; set; }
+ public virtual DateTime StartTime { get; set; }
+ public virtual DateTime EndTime { get; set; }
+ public virtual Currency StartPrice { get; set; }
+ public virtual Currency CurrentPrice { get; set; }
- [Required]
- [StringLength(50,
- ErrorMessage = "Title cannot be longer than 50 characters")]
- public string Title { get; set; }
+ public Guid? WinningBidId { get; set; }
+ public virtual Bid WinningBid { get; private set; }
- [Required]
- public string Description { get; set; }
+ public bool IsCompleted
+ {
+ get { return EndTime <= DateTime.Now; }
+ }
- [Range(1, 10000,
- ErrorMessage = "The auction's starting price must be at least 1")]
- public decimal StartPrice { get; set; }
+ public virtual bool IsFeaturedAuction { get; private set; }
- public decimal CurrentPrice { get; set; }
+ public virtual ICollection<Bid> Bids { get; set; }
- public DateTime EndTime { get; set; }
+ public virtual ICollection<Category> Categories { get; set; }
+
+ public virtual ICollection<WebsiteImage> Images { get; set; }
+
+ public long OwnerId { get; set; }
+ public virtual User Owner { get; set; }
+
+ public virtual CurrencyCode CurrencyCode
+ {
+ get
+ {
+ return (CurrentPrice != null) ? CurrentPrice.Code : null;
+ }
+ }
+
+ public Auction()
+ {
+ Bids = new Collection<Bid>();
+ Categories = new Collection<Category>();
+ Images = new Collection<WebsiteImage>();
+ }
+
+ public void FeatureAuction()
+ {
+ IsFeaturedAuction = true;
+ }
+
+ public Bid PostBid(User user, double bidAmount)
+ {
+ return PostBid(user, new Currency(CurrencyCode, bidAmount));
+ }
+
+ public Bid PostBid(User user, Currency bidAmount)
+ {
+ Contract.Requires(user != null);
+
+ if (bidAmount.Code != CurrencyCode)
+ throw new InvalidBidException(bidAmount, WinningBid);
+
+ if (bidAmount.Value <= CurrentPrice.Value)
+ throw new InvalidBidException(bidAmount, WinningBid);
+
+ var bid = new Bid(user, this, bidAmount);
+
+ CurrentPrice = bidAmount;
+ WinningBidId = bid.Id;
+
+ Bids.Add(bid);
+
+ return bid;
+ }
+
+
+ public class Metadata
+ {
+ [InverseProperty("Auction")]
+ public object Bids;
+
+ public object Categories;
+
+ [Required]
+ public object CurrentPrice;
+
+ [Required]
+ public object Description;
+
+ [Required]
+ public object EndTime;
+
+ [InverseProperty("Selling")]
+ public object Owner;
+
+ [Required]
+ [ForeignKey("Owner")]
+ public object OwnerId;
+
+ [Required]
+ public object StartTime;
+
+ [Required, StringLength(500)]
+ public object Title;
+
+ [ForeignKey("WinningBid")]
+ public object WinningBidId;
+ }
+ }
+
+ public class InvalidBidException : Exception
+ {
+ public Currency BidAmount { get; set; }
+ public Bid WinningBid { get; set; }
+
+ public InvalidBidException(Currency bidAmount, Bid winningBid = null)
+ {
+ BidAmount = bidAmount;
+ WinningBid = winningBid;
+ }
}
+
+
+ public static class AuctionExtensions
+ {
+
+ public static IEnumerable<Auction> Active(this IEnumerable<Auction> auctions)
+ {
+ return auctions.Where(x => x.IsCompleted == false);
+ }
+
+ public static IEnumerable<Auction> Featured(this IEnumerable<Auction> auctions)
+ {
+ return auctions.Where(x => x.IsFeaturedAuction);
+ }
+
+ }
+
}
@@ -0,0 +1,71 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.Contracts;
+
+namespace Ebuy
+{
+ public class Bid : Entity<Guid>, IEquatable<Bid>
+ {
+ public Currency Amount { get; private set; }
+
+ public virtual Auction Auction { get; private set; }
+
+ public DateTime Timestamp { get; private set; }
+
+ public virtual User User { get; private set; }
+
+ public bool IsWinningBid
+ {
+ get
+ {
+ return Auction != null
+ && Id == Auction.WinningBidId;
+ }
+ }
+
+
+ public Bid(User user, Auction auction, Currency price)
+ {
+ Contract.Requires(user != null);
+ Contract.Requires(auction != null);
+ Contract.Requires(price != null);
+
+ User = user;
+ Auction = auction;
+ Amount = price;
+ Timestamp = DateTime.Now;
+ }
+
+ private Bid()
+ {
+ }
+
+ public bool Equals(Bid other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return other.Id.Equals(Id);
+ }
+
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
+ }
+
+
+ public class Metadata
+ {
+ [Required]
+ public object Auction;
+
+ [Required]
+ public object Amount;
+
+ [Required]
+ public object Timestamp;
+
+ [Required]
+ public object User;
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 491b747

Please sign in to comment.