Exercise Files

This commit is contained in:
Jess Chadwick
2018-06-06 23:57:58 -04:00
commit 20458e435e
4436 changed files with 1359080 additions and 0 deletions

View File

@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
namespace HPlusSports.Models
{
public class Category
{
public long Id { get; set; }
[Required]
public string Key { get; set; }
[Required]
public string Name { get; set; }
public long? ImageId { get; set; }
public virtual Image Image { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
namespace HPlusSports
{
public class EntityNotFoundException : ApplicationException
{
public object Id { get; }
public Type Type { get; }
public EntityNotFoundException(Type type, object id)
: base($"Entity ${id?.ToString()} of type ${type?.Name} not found.")
{
Type = type;
Id = id;
}
}
public class EntityNotFoundException<T> : EntityNotFoundException
{
public EntityNotFoundException(object id) : base(typeof(T), id)
{
}
}
}

View File

@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using HPlusSports.Models;
using System.Text.RegularExpressions;
namespace HPlusSports
{
public class HPlusSportsDbContextInitializer
: DropCreateDatabaseIfModelChanges<HPlusSportsDbContext>
{
protected override void Seed(HPlusSportsDbContext context)
{
new SeedData().Populate(context);
}
}
internal class SeedData
{
static readonly Random Random = new Random(1);
public const string TestUserId = "demo@hplussports.com";
static readonly IList<string> UserIds =
Enumerable.Range(0, 10)
.Select(x => $"user{x}")
.Concat(new[] { TestUserId })
.ToArray();
public void Populate(HPlusSportsDbContext context)
{
var doc = ReadTestData();
Populate(context, doc);
}
internal void Populate(HPlusSportsDbContext context, XDocument doc)
{
var categories = doc.Descendants("Categories").Descendants("Category")
.Select(x => new Category
{
Key = ToKey(x.Element("Name").Value),
Name = x.Element("Name").Value,
Image = new Image { Url = x.Element("ImageUrl").Value },
})
.ToArray();
context.Images.AddRange(categories.Select(x => x.Image));
context.SaveChanges();
context.Categories.AddRange(categories);
context.SaveChanges();
var products = doc.Descendants("Product")
.Select(x =>
{
var product = new Product
{
CategoryId = categories.First(cat => cat.Name == x.Element("Category").Value).Id,
Name = x.Element("Name").Value,
Description = StripHtml(x.Element("Description").Value),
MSRP = double.Parse(x.Element("MSRP").Value),
Price = double.Parse(x.Element("Price").Value),
SKU = x.Element("SKU").Value,
Summary = x.Element("Summary").Value,
LastUpdated = DateTime.UtcNow,
LastUpdatedUserId = "admin@hplussports.com",
ThumbnailImage = new Image { Url = x.Element("ThumbnailImageUrl").Value },
};
product.Images.Add(new Image { Url = x.Element("ImageUrl").Value });
return product;
})
.ToArray();
context.Products.AddRange(products);
context.SaveChanges();
var reviews = context.Products.SelectMany(GenerateReviews);
context.Reviews.AddRange(reviews);
context.SaveChanges();
}
IEnumerable<Review> GenerateReviews(Product product)
{
return Enumerable.Range(0, Random.Next(10))
.Select(i =>
new Review
{
SKU = product.SKU,
UserId = UserIds[Random.Next(0, UserIds.Count)],
Rating = Random.Next(3, 5),
});
}
private static string ToKey(string val)
{
return val
.Replace(" ", "-")
.Replace("--", "-")
.Replace("--", "-")
.ToLowerInvariant();
}
private static XDocument ReadTestData()
{
var set = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var stream = typeof(SeedData).Assembly.GetManifestResourceStream("HPlusSports.TestData.xml"))
using (var reader = new StreamReader(stream))
{
return XDocument.Parse(reader.ReadToEnd());
}
}
private static string StripHtml(string source)
{
return
Regex.Replace(
Regex.Replace(
source,
"<[^>]*>",
""
),
"&#[^;]*;",
""
)
.Trim();
}
}
}

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using HPlusSports.Models;
namespace HPlusSports
{
public class HPlusSportsDbContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Image> Images { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Review> Reviews { get; set; }
public DbSet<ShoppingCart> ShoppingCarts { get; set; }
public DbSet<ShoppingCartItem> ShoppingCartItems { get; set; }
public HPlusSportsDbContext()
: this("HPlusSports")
{
}
public HPlusSportsDbContext(string connectionName)
: base(connectionName)
{
}
public Product FindProductBySku(string sku)
=> Products.FirstOrDefault(x => x.SKU == sku);
public ProductRating GetProductRating(string sku)
{
var reviews = Reviews.Where(x => x.SKU == sku);
return new ProductRating
{
SKU = sku,
Rating = reviews.Average(x => (double?)x.Rating),
ReviewCount = reviews.Count(),
};
}
public IQueryable<ProductRating> GetProductRatings(IEnumerable<string> skus)
{
return
Reviews
.Where(x => skus.Distinct().Contains(x.SKU))
.GroupBy(x => x.SKU)
.Select(reviews => new ProductRating
{
SKU = reviews.Key,
Rating = reviews.Average(x => x.Rating),
ReviewCount = reviews.Count(),
});
}
}
}

View File

@ -0,0 +1,13 @@
namespace HPlusSports.Models
{
public class Image
{
public long Id { get; set; }
public string Url { get; set; }
public byte[] Content { get; set; }
public string ContentType { get; set; }
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace HPlusSports.Models
{
public class Product
{
public long Id { get; set; }
[Required]
public long CategoryId { get; set; }
[Required]
public string SKU { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Text)]
public string Summary { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Range(minimum: 0, maximum: double.MaxValue)]
[DataType(DataType.Currency)]
public double MSRP { get; set; }
[Range(minimum: 0, maximum: double.MaxValue)]
[DataType(DataType.Currency)]
public double Price { get; set; }
[Required]
[Display(Name = "Last Updated By")]
public DateTime LastUpdated { get; set; }
[Required]
[Display(Name = "Last Update Timestamp")]
public string LastUpdatedUserId { get; set; }
[NotMapped]
public virtual Category Category { get; set; }
public long? ThumbnailImageId { get; set; }
public virtual Image ThumbnailImage { get; set; }
public virtual ICollection<Image> Images { get; private set; }
public Product()
{
Images = new List<Image>();
}
}
}

View File

@ -0,0 +1,9 @@
namespace HPlusSports.Models
{
public class ProductRating
{
public string SKU { get; set; }
public double? Rating { get; set; }
public int ReviewCount { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace HPlusSports.Models
{
public class Review
{
public long Id { get; set; }
public string UserId { get; set; }
public string SKU { get; set; }
[Range(minimum: 1, maximum: 5)]
public int Rating { get; set; }
[DataType(DataType.MultilineText)]
public string Comments { get; set; }
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace HPlusSports.Models
{
public class ShoppingCart
{
public long Id { get; set; }
public string UserId { get; set; }
[DataType(DataType.Currency)]
public double Tax { get; set; }
[DataType(DataType.Currency)]
public double Shipping { get; set; }
[DataType(DataType.Currency)]
public double Total
{
get { return Subtotal + Tax + Shipping; }
}
public string Coupon { get; set; }
public virtual ICollection<ShoppingCartItem> Items { get; private set; }
[DataType(DataType.Currency)]
public double Subtotal
{
get { return Items.Sum(x => x.Total); }
}
public ShoppingCart()
{
Items = new List<ShoppingCartItem>();
}
public void Recalculate()
{
Shipping = Subtotal * 0.1;
Tax = Subtotal * 0.07;
}
}
}

View File

@ -0,0 +1,37 @@
using System.ComponentModel.DataAnnotations;
namespace HPlusSports.Models
{
public class ShoppingCartItem
{
public long Id { get; set; }
[Required]
public string SKU { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
[Range(minimum: 0, maximum: double.MaxValue)]
public double MSRP { get; set; }
[DataType(DataType.Currency)]
[Range(minimum: 0, maximum: double.MaxValue)]
public double Price { get; set; }
[Range(minimum: 0, maximum: int.MaxValue)]
public int Quantity { get; set; }
[DataType(DataType.Currency)]
public double Total
{
get { return Price * Quantity; }
}
public ShoppingCartItem()
{
}
}
}

View File

@ -0,0 +1,37 @@
using System.ComponentModel.DataAnnotations;
namespace HPlusSports.Models
{
public class UpdateProductRequest
{
[Required]
public long Id { get; set; }
[Required]
public long CategoryId { get; set; }
[Required]
public string SKU { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Text)]
public string Summary { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Range(minimum: 0, maximum: double.MaxValue)]
[DataType(DataType.Currency)]
public double MSRP { get; set; }
[Range(minimum: 0, maximum: double.MaxValue)]
[DataType(DataType.Currency)]
public double Price { get; set; }
public string LastUpdatedUserId { get; set; }
}
}