Witam,
piszę aplikację internetową w ASP.NET MVC 5 przy użyciu Entity Fremowork. Mam problem z jej architekturą.
Mam dwa projekty (w solution)
- Projekt z danymi.
- encje
- generyczna klasa repozytorium
- unit of work zawierający instancje DbContextu oraz instancje konkretnych repozytoriów
- Projekt MVC z referencją do projektu 1.
- kontrolery
- viewmodele
itd.
Problem
Użytkownik wypełnia formularz. Podaje dane, m.in. nazwę drużyny oraz nazwy graczy biorących udział w meczu. Główny problem polega na tym gdzie wstawić kawałek kodu, który w bazie danych wyszukuje czy dana nazwa drużyny już istnieje, to samo z graczami, a następnie tworzy nowe encje lub używa istniejących. Nazwałbym to mapowaniem ViewModelu do encjji.
Bardzo bym prosił o jakąś poradę jak to powinno wyglądać oraz o ocenę czy sama idea repozytoriów i unit of work jest dobrze zaimplementowana.
Poniżej kawałek kodu, który obecnie znajduje się w akcji kontrolera, która obsługuje dane przychodzące z formularza. Działa, ale pewnie akcja kontrolera to nie miejsce gdzie ten kod powinien się znajdować oraz sam kod jest za długi jak na jedną metodę.
[HttpPost]
public ActionResult Create(AddMatchViewModel viewModel)
{
if (ModelState.IsValid)
{
Team teamA = unitOfWork.TeamRepository.Get(m => m.Name == viewModel.TeamAName).FirstOrDefault();
Team teamB = unitOfWork.TeamRepository.Get(m => m.Name == viewModel.TeamBName).FirstOrDefault();
var matchup = new Matchup()
{
TeamA = teamA ?? new Team() { Name = viewModel.TeamAName },
TeamB = teamB ?? new Team() { Name = viewModel.TeamBName }
};
foreach (var result in viewModel.MapResults)
{
Map map = unitOfWork.MapRepository.Get(m => m.Name == result.MapName).FirstOrDefault();
var mapResult = new MapResult()
{
Map = map ?? new Map() { Name = result.MapName },
TeamAScore = result.TeamAScore,
TeamBScore = result.TeamBScore
};
matchup.MapResults.Add(mapResult);
}
for (int playerCounter = 0; playerCounter < viewModel.PlayerResults.Count; playerCounter++)
{
var result = viewModel.PlayerResults[playerCounter];
var player = unitOfWork.PlayerRepository.Get(p => p.Name == result.PlayerName).FirstOrDefault()
?? new Player() { Name = result.PlayerName };
for (int mapCounter = 0; mapCounter < viewModel.NumberOfMaps; mapCounter++)
{
var playerResult = new PlayerResult()
{
Team = playerCounter < 5 ? teamA : teamB,
Player = player,
Rating = result.Ratings[mapCounter]
};
((List<MapResult>)matchup.MapResults)[mapCounter].PlayerResults.Add(playerResult);
}
}
unitOfWork.MatchupRepository.Add(matchup);
unitOfWork.Save();
return RedirectToAction("Index");
}
return View();
}
Viewmodele
public class AddMatchViewModel
{
public DateTime DateTime { get; set; }
public string TeamAName { get; set; }
public string TeamBName { get; set; }
public int NumberOfMaps { get; set; }
public List<MapResultViewModel> MapResults { get; set; } = new List<MapResultViewModel>(3);
public List<PlayerResultViewModel> PlayerResults { get; set; }
}
public class PlayerResultViewModel
{
public string PlayerName { get; set; }
public List<double> Ratings { get; set; }
}
public class MapResultViewModel
{
public string MapName { get; set; }
public int TeamAScore { get; set; }
public int TeamBScore { get; set; }
}
Encje (Team, Map oraz Player zawierają tylko int Id oraz string Name, nie będę zaśmiecał):
public class Matchup
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public Team TeamA { get; set; }
public Team TeamB { get; set; }
public ICollection<MapResult> MapResults { get; set; }
}
public class MapResult
{
public int Id { get; set; }
public Matchup Match { get; set; }
public int TeamAScore { get; set; }
public int TeamBScore { get; set; }
public Map Map { get; set; }
public ICollection<PlayerResult> PlayerResults { get; set; }
}
public class PlayerResult
{
public int Id { get; set; }
public MapResult MapResult { get; set; }
public Player Player { get; set; }
public Team Team { get; set; }
public double Rating { get; set; }
}
Repozytorium generyczne
public class GenericRepository<T> where T : class
{
public Database Context { get; set; }
public GenericRepository(Database context)
{
Context = context;
}
public virtual IQueryable<T> Get(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate);
}
public virtual T GetById(int id)
{
return Context.Set<T>().Find(id);
}
public virtual IQueryable<T> GetAll()
{
IQueryable<T> all = Context.Set<T>();
return all;
}
public virtual void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public virtual void Delete(T entity)
{
Context.Set<T>().Remove(entity);
}
}
Unit of work
public class UnitOfWork
{
private Database context = new Database();
private GenericRepository<Matchup> matchupRepository;
private GenericRepository<Team> teamRepository;
private GenericRepository<Map> mapRepository;
private GenericRepository<Player> playerRepository;
public GenericRepository<Matchup> MatchupRepository
{
get
{
if(this.matchupRepository == null)
this.matchupRepository = new GenericRepository<Matchup>(context);
return this.matchupRepository;
}
}
public GenericRepository<Team> TeamRepository
{
get
{
if (this.teamRepository == null)
this.teamRepository = new GenericRepository<Team>(context);
return this.teamRepository;
}
}
public GenericRepository<Map> MapRepository
{
get
{
if (this.mapRepository == null)
this.mapRepository = new GenericRepository<Map>(context);
return this.mapRepository;
}
}
public GenericRepository<Player> PlayerRepository
{
get
{
if (this.playerRepository == null)
this.playerRepository = new GenericRepository<Player>(context);
return this.playerRepository;
}
}
public void Save()
{
context.SaveChanges();
}
}