From e6aed79fa9803fc16b874964622b406ef2a4578b Mon Sep 17 00:00:00 2001 From: chsakell Date: Wed, 28 Sep 2016 13:21:28 +0300 Subject: [PATCH] added Data, Models, EntityFramework --- Controllers/FeedsController.cs | 24 +++-- Data/Abstract/IEntityBaseRepository.cs | 25 ++++++ Data/Abstract/IRepositories.cs | 13 +++ Data/LiveGameContext.cs | 36 ++++++++ Data/LiveGameDbInitializer.cs | 74 ++++++++++++++++ Data/Repositories/EntityBaseRepository.cs | 102 ++++++++++++++++++++++ Data/Repositories/FeedRepository.cs | 12 +++ Data/Repositories/MatchRepository.cs | 12 +++ Models/Feed.cs | 13 +++ Models/IEntityBase.cs | 12 +++ Models/Match.cs | 22 +++++ Startup.cs | 12 +++ app/app.component.ts | 3 +- app/home/home.component.ts | 3 +- app/shared/feed.service.ts | 20 +---- app/shared/interfaces.ts | 20 +++++ project.json | 3 + 17 files changed, 378 insertions(+), 28 deletions(-) create mode 100644 Data/Abstract/IEntityBaseRepository.cs create mode 100644 Data/Abstract/IRepositories.cs create mode 100644 Data/LiveGameContext.cs create mode 100644 Data/LiveGameDbInitializer.cs create mode 100644 Data/Repositories/EntityBaseRepository.cs create mode 100644 Data/Repositories/FeedRepository.cs create mode 100644 Data/Repositories/MatchRepository.cs create mode 100644 Models/Feed.cs create mode 100644 Models/IEntityBase.cs create mode 100644 Models/Match.cs create mode 100644 app/shared/interfaces.ts diff --git a/Controllers/FeedsController.cs b/Controllers/FeedsController.cs index 6cb1dec..a631aa4 100644 --- a/Controllers/FeedsController.cs +++ b/Controllers/FeedsController.cs @@ -5,27 +5,37 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR.Infrastructure; using LiveGameFeed.Hubs; +using LiveGameFeed.Data.Abstract; +using LiveGameFeed.Models; namespace LiveGameFeed.Controllers { [Route("api/[controller]")] public class FeedsController : ApiHubController { - public FeedsController(IConnectionManager signalRConnectionManager) - : base(signalRConnectionManager) { } - + IFeedRepository _feedRepository; + public FeedsController( + IConnectionManager signalRConnectionManager, + IFeedRepository feedRepository) + : base(signalRConnectionManager) + { + _feedRepository = feedRepository; + } + // GET api/values [HttpGet] - public IEnumerable Get() + public IEnumerable Get() { - return new string[] { "value1", "value2" }; + IEnumerable _feeds = _feedRepository.GetAll(); + + return _feeds; } // GET api/values/5 [HttpGet("{id}")] - public string Get(int id) + public Feed Get(int id) { - return "value"; + return _feedRepository.GetSingle(id); } // POST api/values diff --git a/Data/Abstract/IEntityBaseRepository.cs b/Data/Abstract/IEntityBaseRepository.cs new file mode 100644 index 0000000..ce85e83 --- /dev/null +++ b/Data/Abstract/IEntityBaseRepository.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Linq.Expressions; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data.Abstract +{ + public interface IEntityBaseRepository where T : class, IEntityBase, new() + { + IEnumerable AllIncluding(params Expression>[] includeProperties); + IEnumerable GetAll(); + int Count(); + T GetSingle(int id); + T GetSingle(Expression> predicate); + T GetSingle(Expression> predicate, params Expression>[] includeProperties); + IEnumerable FindBy(Expression> predicate); + void Add(T entity); + void Update(T entity); + void Delete(T entity); + void DeleteWhere(Expression> predicate); + void Commit(); + } +} diff --git a/Data/Abstract/IRepositories.cs b/Data/Abstract/IRepositories.cs new file mode 100644 index 0000000..81da001 --- /dev/null +++ b/Data/Abstract/IRepositories.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data.Abstract +{ + public interface IMatchRepository : IEntityBaseRepository { } + + public interface IFeedRepository : IEntityBaseRepository { } + +} diff --git a/Data/LiveGameContext.cs b/Data/LiveGameContext.cs new file mode 100644 index 0000000..ef0f320 --- /dev/null +++ b/Data/LiveGameContext.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LiveGameFeed.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace LiveGameFeed.Data +{ + public class LiveGameContext : DbContext + { + public DbSet Matches { get; set; } + public DbSet Feeds { get; set; } + + public LiveGameContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) + { + relationship.DeleteBehavior = DeleteBehavior.Restrict; + } + + modelBuilder.Entity() + .ToTable("Match"); + + modelBuilder.Entity() + .ToTable("Feed"); + + modelBuilder.Entity() + .Property(f => f.MatchId) + .IsRequired(); + } + } +} diff --git a/Data/LiveGameDbInitializer.cs b/Data/LiveGameDbInitializer.cs new file mode 100644 index 0000000..c05895b --- /dev/null +++ b/Data/LiveGameDbInitializer.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data +{ + public class LiveGameDbInitializer + { + private static LiveGameContext context; + public static void Initialize(IServiceProvider serviceProvider) + { + context = (LiveGameContext)serviceProvider.GetService(typeof(LiveGameContext)); + + InitializeSchedules(); + } + + private static void InitializeSchedules() + { + if (!context.Matches.Any()) + { + Match match_01 = new Match + { + Host = "Panathinaikos", + Guest = "Olimpiakos", + HostScore = 3, + GuestScore = 1, + MatchDate = DateTime.Now, + League = "FootballLeauge", + Feeds = new List + { + new Feed() + { + Description = "Match started", + MatchId = 1 + }, + new Feed() + { + Description = "Goal for Panathinaikos", + MatchId = 1 + }, + } + }; + Match match_02 = new Match + { + Host = "Real Madrit FC", + Guest = "Barchelona", + HostScore = 5, + GuestScore = 3, + MatchDate = DateTime.Now, + League = "Spanish League", + Feeds = new List + { + new Feed() + { + Description = "Match started", + MatchId = 2 + }, + new Feed() + { + Description = "Goal for Real Madrid", + MatchId = 2 + }, + } + }; + + context.Matches.Add(match_01); context.Matches.Add(match_02); + + context.SaveChanges(); + } + } + } +} \ No newline at end of file diff --git a/Data/Repositories/EntityBaseRepository.cs b/Data/Repositories/EntityBaseRepository.cs new file mode 100644 index 0000000..5d998b6 --- /dev/null +++ b/Data/Repositories/EntityBaseRepository.cs @@ -0,0 +1,102 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using LiveGameFeed.Data.Abstract; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data.Repositories +{ + public class EntityBaseRepository : IEntityBaseRepository + where T : class, IEntityBase, new() + { + + private LiveGameContext _context; + + #region Properties + public EntityBaseRepository(LiveGameContext context) + { + _context = context; + } + #endregion + public virtual IEnumerable GetAll() + { + return _context.Set().AsEnumerable(); + } + + public virtual int Count() + { + return _context.Set().Count(); + } + public virtual IEnumerable AllIncluding(params Expression>[] includeProperties) + { + IQueryable query = _context.Set(); + foreach (var includeProperty in includeProperties) + { + query = query.Include(includeProperty); + } + return query.AsEnumerable(); + } + + public T GetSingle(int id) + { + return _context.Set().FirstOrDefault(x => x.Id == id); + } + + public T GetSingle(Expression> predicate) + { + return _context.Set().FirstOrDefault(predicate); + } + + public T GetSingle(Expression> predicate, params Expression>[] includeProperties) + { + IQueryable query = _context.Set(); + foreach (var includeProperty in includeProperties) + { + query = query.Include(includeProperty); + } + + return query.Where(predicate).FirstOrDefault(); + } + + public virtual IEnumerable FindBy(Expression> predicate) + { + return _context.Set().Where(predicate); + } + + public virtual void Add(T entity) + { + EntityEntry dbEntityEntry = _context.Entry(entity); + _context.Set().Add(entity); + } + + public virtual void Update(T entity) + { + EntityEntry dbEntityEntry = _context.Entry(entity); + dbEntityEntry.State = EntityState.Modified; + } + public virtual void Delete(T entity) + { + EntityEntry dbEntityEntry = _context.Entry(entity); + dbEntityEntry.State = EntityState.Deleted; + } + + public virtual void DeleteWhere(Expression> predicate) + { + IEnumerable entities = _context.Set().Where(predicate); + + foreach(var entity in entities) + { + _context.Entry(entity).State = EntityState.Deleted; + } + } + + public virtual void Commit() + { + _context.SaveChanges(); + } + } +} diff --git a/Data/Repositories/FeedRepository.cs b/Data/Repositories/FeedRepository.cs new file mode 100644 index 0000000..a7103ab --- /dev/null +++ b/Data/Repositories/FeedRepository.cs @@ -0,0 +1,12 @@ +using LiveGameFeed.Data.Abstract; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data.Repositories +{ + public class FeedRepository : EntityBaseRepository, IFeedRepository + { + public FeedRepository(LiveGameContext context) + : base(context) + { } + } +} diff --git a/Data/Repositories/MatchRepository.cs b/Data/Repositories/MatchRepository.cs new file mode 100644 index 0000000..b857346 --- /dev/null +++ b/Data/Repositories/MatchRepository.cs @@ -0,0 +1,12 @@ +using LiveGameFeed.Data.Abstract; +using LiveGameFeed.Models; + +namespace LiveGameFeed.Data.Repositories +{ + public class MatchRepository : EntityBaseRepository, IMatchRepository + { + public MatchRepository(LiveGameContext context) + : base(context) + { } + } +} diff --git a/Models/Feed.cs b/Models/Feed.cs new file mode 100644 index 0000000..d31af9b --- /dev/null +++ b/Models/Feed.cs @@ -0,0 +1,13 @@ +using System; + +namespace LiveGameFeed.Models +{ + public class Feed : IEntityBase + { + public int Id { get; set; } + public string Description { get; set; } + public DateTime CreatedAt { get; set; } + public int MatchId { get; set; } + public Match Match { get; set; } + } +} diff --git a/Models/IEntityBase.cs b/Models/IEntityBase.cs new file mode 100644 index 0000000..c189729 --- /dev/null +++ b/Models/IEntityBase.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace LiveGameFeed.Models +{ + public interface IEntityBase + { + int Id { get; set; } + } +} diff --git a/Models/Match.cs b/Models/Match.cs new file mode 100644 index 0000000..39387ce --- /dev/null +++ b/Models/Match.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace LiveGameFeed.Models +{ + public class Match : IEntityBase + { + public Match() + { + Feeds = new List(); + } + public int Id { get; set; } + public string Host { get; set; } + public string Guest { get; set; } + public int HostScore { get; set; } + public int GuestScore { get; set; } + public DateTime MatchDate { get; set; } + public string League { get; set; } + + public ICollection Feeds { get; set; } + } +} diff --git a/Startup.cs b/Startup.cs index 478c186..9cfcac0 100644 --- a/Startup.cs +++ b/Startup.cs @@ -2,8 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using LiveGameFeed.Data; +using LiveGameFeed.Data.Repositories; +using LiveGameFeed.Data.Abstract; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -27,6 +31,12 @@ namespace LiveGameFeed // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddDbContext(options => options.UseInMemoryDatabase()); + + // Repositories + services.AddScoped(); + services.AddScoped(); + // Add framework services. services.AddMvc(); @@ -61,6 +71,8 @@ namespace LiveGameFeed template: "{controller=Home}/{action=Index}/{id?}"); }); app.UseSignalR(); + + LiveGameDbInitializer.Initialize(app.ApplicationServices); } } } diff --git a/app/app.component.ts b/app/app.component.ts index 237ade2..7617329 100644 --- a/app/app.component.ts +++ b/app/app.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; -import { FeedService, ConnectionState } from './shared/feed.service' +import { FeedService } from './shared/feed.service'; +import { ConnectionState } from './shared/interfaces'; @Component({ selector: 'my-app', diff --git a/app/home/home.component.ts b/app/home/home.component.ts index 5dfb75c..5da5a32 100644 --- a/app/home/home.component.ts +++ b/app/home/home.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; -import { FeedService, ConnectionState } from '../shared/feed.service'; +import { FeedService } from '../shared/feed.service'; +import { ConnectionState } from '../shared/interfaces'; @Component({ selector: 'home', diff --git a/app/shared/feed.service.ts b/app/shared/feed.service.ts index bcc3c56..4479038 100644 --- a/app/shared/feed.service.ts +++ b/app/shared/feed.service.ts @@ -5,25 +5,7 @@ import 'rxjs/add/operator/toPromise'; import { Observable } from "rxjs/Observable"; import { Subject } from "rxjs/Subject"; -interface FeedSignalR extends SignalR { - broadcaster: FeedProxy -} - -interface FeedProxy { - client: FeedClient -} - -interface FeedClient { - userConnected: (user: any) => void; - userDisconnected: (id: string) => void; - messageReceived: (message: string) => void; -} - -export enum ConnectionState { - Connected = 1, - Disconnected = 2, - Error = 3 -} +import { FeedSignalR, FeedProxy, FeedClient, ConnectionState } from './interfaces'; @Injectable() export class FeedService { diff --git a/app/shared/interfaces.ts b/app/shared/interfaces.ts new file mode 100644 index 0000000..c69b3f3 --- /dev/null +++ b/app/shared/interfaces.ts @@ -0,0 +1,20 @@ +/* SignalR related interfaces */ +export interface FeedSignalR extends SignalR { + broadcaster: FeedProxy +} + +export interface FeedProxy { + client: FeedClient +} + +export interface FeedClient { + userConnected: (user: any) => void; + userDisconnected: (id: string) => void; + messageReceived: (message: string) => void; +} + +export enum ConnectionState { + Connected = 1, + Disconnected = 2, + Error = 3 +} \ No newline at end of file diff --git a/project.json b/project.json index 9f5b1e6..4b5f676 100644 --- a/project.json +++ b/project.json @@ -11,6 +11,9 @@ "Microsoft.AspNetCore.SignalR.Server": "0.2.0-*", "Microsoft.AspNetCore.StaticFiles": "1.1.0-*", "Microsoft.AspNetCore.WebSockets": "0.2.0-*", + "Microsoft.EntityFrameworkCore": "1.0.1", + "Microsoft.EntityFrameworkCore.InMemory": "1.0.0", + "Microsoft.EntityFrameworkCore.Relational": "1.0.1", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",