Files
MileageTraker/Web/DAL/DataService.cs
T
2014-02-02 10:19:02 -05:00

575 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using MileageTraker.Web.Context;
using MileageTraker.Web.Models;
using MileageTraker.Web.Utility;
using MileageTraker.Web.ViewModels;
using MileageTraker.Web.ViewModels.Log;
using MileageTraker.Web.ViewModels.Vehicle;
namespace MileageTraker.Web.DAL
{
public class DataService : IDisposable
{
private readonly MileageTrakerContext _db = new MileageTrakerContext();
public void Dispose()
{
_db.Dispose();
}
#region Log
public void AddLog(Log log)
{
log.Created = DateTime.Now;
_db.Logs.Add(log);
// update previous log links
var previousLog = SearchPreviousLog(log);
log.VehiclePreviousLog = previousLog;
var nextLog = SearchNextLog(log);
if (nextLog != null)
{
nextLog.VehiclePreviousLog = log;
nextLog.User = _db.Users.Find(nextLog.User.UserId);
_db.Entry(nextLog).State = EntityState.Modified;
}
_db.SaveChanges();
UpdateCurrentOdometer(log.VehicleId);
}
public void UpdateLog(Log log)
{
// note: assumes log is already attached to current context
// remove from the list
var nextLog =
(from l in _db.Logs
where l.VehiclePreviousLogId == log.LogId
select l).FirstOrDefault();
if (nextLog != null)
{
nextLog.VehiclePreviousLogId = log.VehiclePreviousLogId;
nextLog.User = _db.Users.Find(nextLog.User.UserId);
_db.Entry(nextLog).State = EntityState.Modified;
}
log.VehiclePreviousLog = null;
log.VehiclePreviousLogId = null;
// add it back in new position
var previousLog = SearchPreviousLog(log);
if (previousLog != null)
log.VehiclePreviousLogId = previousLog.LogId;
var newNextLog = SearchNextLog(log);
if (newNextLog != null)
{
newNextLog.VehiclePreviousLogId = log.LogId;
newNextLog.User = _db.Users.Find(newNextLog.User.UserId);
_db.Entry(newNextLog).State = EntityState.Modified;
}
log.User = _db.Users.Find(log.User.UserId);
_db.Entry(log).State = EntityState.Modified;
_db.SaveChanges();
UpdateCurrentOdometer(log.VehicleId);
}
public void DeleteLog(int id)
{
var log = _db.Logs.Find(id);
var nextLog = GetNextLog(log.LogId);
if (nextLog != null)
{
nextLog.VehiclePreviousLog = log.VehiclePreviousLog;
nextLog.User = _db.Users.Find(nextLog.User.UserId);
_db.Entry(nextLog).State = EntityState.Modified;
}
_db.Logs.Remove(log);
_db.SaveChanges();
UpdateCurrentOdometer(log.VehicleId);
}
public IQueryable<Log> GetLogs()
{
return _db.Logs;
}
public Log GetLog(int id)
{
return _db.Logs.Find(id);
}
public Log GetNextLog(int id)
{
return
(from l in _db.Logs
where l.VehiclePreviousLogId == id
select l).FirstOrDefault();
}
public IEnumerable<int> GetValidLogYears()
{
return
from l in GetLogs()
group l by new {year = l.Date.Year}
into y
orderby y.Key descending
select y.Key.year;
}
public IEnumerable<int> GetValidLogMonths(int year)
{
var start = new DateTime(year, 1, 1);
var end = new DateTime(year + 1, 1, 1);
return
from l in GetLogs()
where l.Date >= start && l.Date < end
group l by new { month = l.Date.Month }
into m
orderby m.Key descending
select m.Key.month;
}
public IEnumerable<LogIndexViewModel> GetLogIndexViewModels(IQueryable<Log> logs)
{
var t =
from log in logs
select new { log, log.VehiclePreviousLog };
return from l in t.ToList()
select new LogIndexViewModel(l.log, l.VehiclePreviousLog);
}
public IEnumerable<VehicleMileageItem> GetMonthlyVehicleMileageItems(LogQueryViewModel query)
{
var items =
from l in
from log in FilterLogs(_db.Logs, query)
let previousLog = log.VehiclePreviousLog
select new {log, previousLog, miles = (previousLog != null ? log.EndOdometer - previousLog.EndOdometer : 0)}
group l by l.log.VehicleId
into g
join v in _db.Vehicles on g.Key equals v.VehicleId
let miles = g.Sum(l => l.miles)
let gasPurchased = g.Sum(l => l.log.GasPurchased)
where miles > 0 || gasPurchased > 0
let logPairs =
from i in g
orderby i.log.Date descending , i.log.EndOdometer descending
select new { PreviousLog = i.previousLog, Log = i.log }
select
new
{
VehicleId = g.Key,
GasPurchased = gasPurchased,
Miles = miles,
v.Prog,
LogPairs = logPairs
};
return items.ToList().Select(i => new VehicleMileageItem
{
VehicleId = i.VehicleId,
GasPurchased = i.GasPurchased,
Miles = i.Miles,
Prog = i.Prog,
LogPairs = i.LogPairs.ToList()
.Select(lp => new Tuple<Log,Log>(lp.PreviousLog, lp.Log))
});
}
public IEnumerable<DriverMileageItem> GetMonthlyDriverMileageItems(LogQueryViewModel query)
{
var items =
from l in
from log in FilterLogs(_db.Logs, query)
let previousLog = log.VehiclePreviousLog
select new { log, previousLog, miles = (previousLog != null ? log.EndOdometer - previousLog.EndOdometer : 0) }
group l by l.log.User into g
let vehicleLogs =
from i in g
group i by i.log.VehicleId into v
from vehicle in _db.Vehicles
where vehicle.VehicleId == v.Key
let vehicleProg = vehicle.Prog
let vehicleMiles = v.Sum(l => l.miles)
let vehicleGasPurchased = v.Sum(l => l.log.GasPurchased)
where vehicleMiles > 0 || vehicleGasPurchased > 0
let vehicleLogPairs =
from i in v
orderby i.log.Date descending, i.log.EndOdometer descending
select new { PreviousLog = i.previousLog, Log = i.log }
select new
{
VehicleId = v.Key,
Prog = vehicleProg,
Miles = vehicleMiles,
GasPurchased = vehicleGasPurchased,
LogPairs = vehicleLogPairs
}
select
new
{
User = g.Key,
VehicleLogs = vehicleLogs
};
return items.ToList().Select(i => new DriverMileageItem
{
DriverName = i.User.FullName,
VehicleMileageItems = i.VehicleLogs.ToList().Select(v => new VehicleMileageItem
{
VehicleId = v.VehicleId,
Prog = v.Prog,
Miles = v.Miles,
GasPurchased = v.GasPurchased,
LogPairs = v.LogPairs.ToList()
.Select(lp => new Tuple<Log, Log>(lp.PreviousLog, lp.Log))
}).ToList()
});
}
public static IQueryable<Log> FilterLogs(IQueryable<Log> logs, LogQueryViewModel query)
{
if (query.Year.HasValue & query.Month.HasValue)
{
var start = new DateTime(query.Year.Value, query.Month.Value, 1);
var end = start.AddMonths(1);
logs = logs.Where(l => l.Date >= start && l.Date < end);
}
if (query.LogType.HasValue)
{
// WTF The specified value is not an instance of type 'Edm.Int32'
logs = logs.Where(query.LogType.Value.GetEqualsPredicate());
}
return logs;
}
public IEnumerable<Log> GetDuplicateLogs(Log log)
{
return
from dbLog in GetLogs().Where(log.LogType.Enum.GetEqualsPredicate())
where
dbLog.Date == log.Date &&
dbLog.EndOdometer == log.EndOdometer &&
dbLog.VehicleId == log.VehicleId
select dbLog;
}
public IEnumerable<Log> GetRecentLogsByUsername(string username)
{
return
(from l in _db.Logs
where l.User.Username == username
orderby l.Created descending
select l)
.Take(3)
.ToList();
}
public Log SearchPreviousLog(Log current)
{
var vehicleId = current.VehicleId;
var date = current.Date;
var endOdometer = current.EndOdometer;
return SearchPreviousLog(endOdometer, vehicleId, date, current.Created, current.LogId);
}
public Log SearchPreviousLog(int endOdometer, string vehicleId, DateTime date, DateTime created, int? excludeLogId = null)
{
return (from pl in _db.Logs
where pl.VehicleId == vehicleId &&
((pl.EndOdometer < endOdometer && pl.Date <= date)
|| (pl.EndOdometer == endOdometer && pl.Date < date)
|| (pl.EndOdometer == endOdometer && pl.Date == date && pl.Created < created))
orderby pl.EndOdometer descending, pl.Date descending, pl.Created descending
select pl)
.FirstOrDefault(l => !excludeLogId.HasValue || l.LogId != excludeLogId.Value);
}
public Log SearchNextLog(Log current)
{
var vehicleId = current.VehicleId;
var date = current.Date;
var endOdometer = current.EndOdometer;
return SearchNextLog(endOdometer, vehicleId, date, current.Created, current.LogId);
}
public Log SearchNextLog(int endOdometer, string vehicleId, DateTime date, DateTime created, int? excludeLogId = null)
{
return (from nl in GetLogs()
where nl.VehicleId == vehicleId &&
((nl.EndOdometer > endOdometer && nl.Date >= date)
|| (nl.EndOdometer == endOdometer && nl.Date > date)
|| (nl.EndOdometer == endOdometer && nl.Date >= date && nl.Created > created))
orderby nl.EndOdometer ascending, nl.Date ascending, nl.Created ascending
select nl)
.FirstOrDefault(l => !excludeLogId.HasValue || l.LogId != excludeLogId.Value);
}
public IEnumerable<PurposeType> GetPurposeTypes()
{
return
(from pt in _db.PurposeTypes
select pt).OrderBy(pt => pt.SortOrder).ToList();
}
public void AddPurposeType(PurposeType purposeType)
{
_db.PurposeTypes.Add(purposeType);
_db.SaveChanges();
}
public void UpdatePurposeType(PurposeType purposeType)
{
_db.Entry(purposeType).State = EntityState.Modified;
_db.SaveChanges();
}
public PurposeType FindPurposeType(int id)
{
return GetPurposeTypes().FirstOrDefault(pt => pt.PurposeTypeId == id);
}
public PurposeType FindPurposeType(string name)
{
if (string.IsNullOrEmpty(name))
return null;
var mpt =
GetPurposeTypes()
.Select(pt =>
Tuple.Create(pt.PurposeTypeId,
Algorithms.Similarity(
pt.Purpose.ToLowerInvariant(),
name.ToLowerInvariant())))
.OrderByDescending(tp => tp.Item2)
.FirstOrDefault(tp => tp.Item2 > .8);
if (mpt != null)
return FindPurposeType(mpt.Item1);
return null;
}
#endregion
#region Vehicle
public void AddVehicle(Vehicle vehicle)
{
if (vehicle.Assigned == "Unassigned")
vehicle.Assigned = null;
_db.Vehicles.Add(vehicle);
_db.SaveChanges();
}
public void UpdateVehicle(Vehicle vehicle)
{
if (vehicle.Assigned == "Unassigned")
vehicle.Assigned = null;
_db.Entry(vehicle).State = EntityState.Modified;
_db.SaveChanges();
}
public IEnumerable<Vehicle> GetVehicles()
{
var vehicles = _db.Vehicles;
return vehicles;
}
public Vehicle GetVehicle(string id)
{
return _db.Vehicles.Find(id);
}
public void UpdateCurrentOdometer(string vehicleId)
{
var mostRecentOdometerQuery =
from log in _db.Logs
where
log.VehicleId == vehicleId
orderby log.Date descending, log.EndOdometer descending
select log;
var mostRecentOdometer = mostRecentOdometerQuery.FirstOrDefault();
var vehicle = _db.Vehicles.Find(vehicleId);
if (mostRecentOdometer != null && mostRecentOdometer.EndOdometer != vehicle.CurrentOdometer)
{
vehicle.CurrentOdometer = mostRecentOdometer.EndOdometer;
UpdateVehicle(vehicle);
}
}
public void ValidateOdometerChronology(string vehicleId, int odometer, DateTime date)
{
var conflictingLog = GetFirstConflictingOdometerChronologyLog(vehicleId, date, odometer);
if (conflictingLog != null)
{
throw new ChronologicalOrderException(
String.Format(
"Odometer of {0} miles on {1:d} conflicts with other logs for vehicle {2}" +
", including an odometer log of {3} miles on {4:d} reported by {5}.",
odometer, date, vehicleId, conflictingLog.EndOdometer, conflictingLog.Date, conflictingLog.User.FullName));
}
}
public Log GetFirstConflictingOdometerChronologyLog(string vehicleId, DateTime date, int odometer)
{
var conflictingLogsQuery =
from log in _db.Logs
let existingDate = log.Date
let existingOdometer = log.EndOdometer
where
log.VehicleId == vehicleId &&
!(existingDate == date
|| existingOdometer == odometer
|| existingDate < date && existingOdometer < odometer
|| existingDate > date && existingOdometer > odometer)
orderby existingOdometer descending
select log;
return conflictingLogsQuery.FirstOrDefault();
}
#endregion
#region City
public string GetCitiesCorrected(string term)
{
var termLower = term.ToLower();
return (from city in GetCities().ToList()
let cityToLower = city.Name.ToLower()
let similarity = Algorithms.Similarity(cityToLower, termLower)
where city.Name.StartsWith(term) || Algorithms.Similarity(cityToLower, termLower) > .8
select city.Name).FirstOrDefault();
}
public IEnumerable<string> GetCitiesAutocomplete(string term)
{
return
from city in GetCities()
where city.Name.StartsWith(term)
select city.Name;
}
private IQueryable<City> GetCities()
{
return _db.Cities;
}
#endregion
#region Membership
public void AddUser(User user)
{
user.Created = DateTime.Now;
_db.Users.Add(user);
_db.SaveChanges();
}
public void UpdateUser(User user)
{
_db.Entry(user).State = EntityState.Modified;
_db.SaveChanges();
}
/// <summary>
/// Update only fields not needing extra membership provider support
/// </summary>
public void UpdateUserPersonalInfo(User user)
{
var original = GetUser(user.UserId);
original.Comment = user.Comment;
original.Email = user.Email;
original.FullName = user.FullName;
original.Username = user.Username;
UpdateUser(original);
}
public void UpdateUserPassword(Guid userId, string password)
{
var user = GetUser(userId);
user.Password = Crypto.HashPassword(password);
user.LastPasswordChangedDate = DateTime.Now;
user.IsLockedOut = false;
user.PasswordFailuresSinceLastSuccess = 0;
user.PasswordResetToken = null;
UpdateUser(user);
}
public void UpdateUserLastActivity(string username)
{
var user = FindUserByUsername(username);
if (user != null)
{
user.LastActivityDate = DateTime.Now;
UpdateUser(user);
}
}
public IQueryable<User> GetUsers()
{
return _db.Users;
}
public User GetUser(Guid guid)
{
return _db.Users.Find(guid);
}
public User FindUserByUsername(string username)
{
return _db.Users.FirstOrDefault(u => username.Equals(u.Username, StringComparison.InvariantCultureIgnoreCase));
}
public User FindUserByFullName(string fullName)
{
return _db.Users.FirstOrDefault(u => fullName.Equals(u.FullName, StringComparison.InvariantCultureIgnoreCase));
}
public User FindUserByEmail(string email)
{
return _db.Users.FirstOrDefault(u => email.Equals(u.Email, StringComparison.InvariantCultureIgnoreCase));
}
public IQueryable<Role> GetRoles()
{
return _db.Roles;
}
public IEnumerable<string> GetUserFullNamesAutocomplete(string term)
{
var termLower = term.ToLower();
return from name in GetUserFullNames()
let nameLower = name.ToLower()
where nameLower.StartsWith(termLower) || Algorithms.Similarity(nameLower, termLower) > .8
select name;
}
public IEnumerable<string> GetUserFullNames()
{
var logNames =
(from l in _db.Users
select l.FullName);
return logNames;
}
#endregion
}
}