static void Main(string[] args) { using var newbieContext = new NewbieContext(); // This works, w/o any Update() statements. //var first = newbieContext.UpdateSchedules.First(); //first.ActiveIndex++; //newbieContext.SaveChanges(); using var newbieContext2 = new NewbieContext(); var strategy1 = newbieContext.Database.CreateExecutionStrategy(); strategy1.Execute(() => { using var transaction1 = newbieContext.Database.BeginTransaction(IsolationLevel.ReadCommitted); using var transaction2 = newbieContext2.Database.BeginTransaction(IsolationLevel.ReadCommitted); var first = newbieContext.UpdateSchedules.First(); first.ActiveIndex += 10; var first2 = newbieContext2.UpdateSchedules.First(); first2.ActiveIndex += 20; newbieContext2.SaveChanges(); Task.Run(() => { Task.Delay(10_000).Wait(); transaction2.Commit(); }); newbieContext.SaveChanges(); // Throws? }); }
private static async Task <List <UserSnapshot> > GetHistories(List <int> osuIds, Bleatingsheep.Osu.Mode mode) { using var newbieContext = new NewbieContext(); var now = DateTimeOffset.Now; var snaps = await newbieContext.UserSnapshots .Where(s => now.Subtract(TimeSpan.FromHours(36)) < s.Date && s.Mode == mode && osuIds.Contains(s.UserId)) .ToListAsync().ConfigureAwait(false); return(snaps .GroupBy(s => s.UserId) .Select(g => g.OrderBy(s => Utilities.DateUtility.GetError(now - TimeSpan.FromHours(24), s.Date)).First()) .ToList()); }
private static async Task <IExecutingResult <T> > TryExecuteAsync <T>(Func <NewbieContext, Task <T> > func) { try { using (var context = new NewbieContext()) { return(new ExecutingResult <T>(await func(context))); } } catch (Exception e) { return(new ExecutingResult <T>(e)); } }
/// <summary> /// Query user play records. /// Parameters must have same number of elements, /// and there must not be any duplicate <c>userId</c> and <c>mode</c> combination. /// </summary> /// <param name="context">Database context to use.</param> /// <param name="userIds">List of queried user ids. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param> /// <param name="modes">List of queried modes. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param> /// <param name="startIndecies">List of first numbers played. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param> /// <returns>A list of user play records.</returns> public static async Task <IList <UserPlayRecord> > GetUserPlayRecordsAsync( NewbieContext context, IEnumerable <int> userIds, IEnumerable <Mode> modes, IEnumerable <int> startIndecies) { var tracking = context.ChangeTracker.QueryTrackingBehavior; context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; // TODO: Verify that there is no repeating conditions (with same userId and mode). // If so, select the minimum of StartNumber. var filters = userIds.Zip(modes).Zip(startIndecies, (tuple, start) => { var(userId, mode) = tuple; return(new PlayRecordQueryTemp { UserId = userId, Mode = mode, StartNumber = start, }); }); var result = await context.Database.CreateExecutionStrategy().ExecuteAsync(async() => { using (await context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted).ConfigureAwait(false)) { await context.PlayRecordQueryTemps.AddRangeAsync(filters).ConfigureAwait(false); await context.SaveChangesAsync().ConfigureAwait(false); return(await(from r in context.UserPlayRecords join f in context.PlayRecordQueryTemps on new { r.UserId, r.Mode } equals new { f.UserId, f.Mode } where r.PlayNumber >= f.StartNumber select r).ToListAsync().ConfigureAwait(false)); } }).ConfigureAwait(false); context.ChangeTracker.QueryTrackingBehavior = tracking; return(result); }
public async Task ProcessAsync(MessageContext superContext, HttpApiClient api) { var context = superContext as GroupMessage; var groupMembers = await api.GetGroupMemberListAsync(context.GroupId); Logger.Debug($"群 {context.GroupId} 开启今日高光,成员共 {groupMembers.Length} 名。"); var stopwatch = Stopwatch.StartNew(); using (var dbContext = new NewbieContext()) { //var bindings = await (from b in dbContext.Bindings // join mi in groupMembers on b.UserId equals mi.UserId // select new { Info = mi, Binding = b.OsuId }).ToListAsync(); ////var history = (from bi in bindings.AsQueryable() //// join ui in motherShip.Userinfo on bi.Binding equals ui.UserId into histories //// select new { bi.Info, bi.Binding, History = histories.OrderByDescending(ui => ui.QueryDate).First() }).ToList(); //var osuIds = bindings.Select(b => b.Binding).Distinct().ToList(); var qqs = groupMembers.Select(mi => mi.UserId).ToList(); var osuIds = await dbContext.Bindings.Where(bi => qqs.Contains(bi.UserId)).Select(bi => bi.OsuId).Distinct().ToListAsync(); Logger.Debug($"找到 {osuIds.Count} 个绑定信息,耗时 {stopwatch.ElapsedMilliseconds}ms。"); Bleatingsheep.Osu.Mode mode = 0; if (!string.IsNullOrEmpty(ModeString)) { try { mode = Bleatingsheep.Osu.ModeExtensions.Parse(ModeString); } catch (FormatException) { // ignore } } stopwatch = Stopwatch.StartNew(); List <UserSnapshot> history = await GetHistories(osuIds, mode).ConfigureAwait(false); Logger.Debug($"找到 {history.Count} 个历史信息,耗时 {stopwatch.ElapsedMilliseconds}ms。"); // Using ConcurrentBag is enough here. ConcurrentDictionary is unnecessary and costly. var nowInfos = new ConcurrentDictionary <int, UserInfo>(10, history.Count); var fails = new BlockingCollection <int>(); stopwatch = Stopwatch.StartNew(); var fetchIds = history.Select(h => (int)h.UserId).Distinct().ToList(); int completes = 0; var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; var tasks = fetchIds.Concat(fails.GetConsumingEnumerable()).Select(async bi => { var(success, userInfo) = await GetCachedUserInfo(bi, (Bleatingsheep.Osu.Mode)mode).ConfigureAwait(false); if (!success) { if (cancellationToken.IsCancellationRequested) { fails.CompleteAdding(); } if (!fails.IsAddingCompleted) { try { fails.Add(bi); } catch (InvalidOperationException) { } } } else { Interlocked.Increment(ref completes); if (completes == fetchIds.Count) { fails.CompleteAdding(); } if (userInfo != null) { nowInfos[bi] = userInfo; } } }).ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); Logger.Debug($"查询 API 花费 {stopwatch.ElapsedMilliseconds}ms,失败 {fails.Count} 个。"); var cps = (from his in history join now in nowInfos on his.UserId equals now.Key where his.UserInfo.PlayCount != now.Value.PlayCount orderby now.Value.Performance - his.UserInfo.Performance descending select new { Old = his.UserInfo, New = now.Value, Meta = his }).ToList(); if (fails.Count > 0) { await api.SendGroupMessageAsync(context.GroupId, $"失败了 {fails.Count} 人。"); } if (cps.Count == 0) { await api.SendMessageAsync(context.Endpoint, "你群根本没有人屙屎。"); return; } else { var increase = cps.Find(cp => cp.Old.Performance != 0 && cp.New.Performance != cp.Old.Performance); var mostPlay = cps.OrderByDescending(cp => cp.New.TotalHits - cp.Old.TotalHits).First(); var sb = new StringBuilder(100); sb.AppendLine("最飞升:"); if (increase != null) { // sb.AppendLine($"{increase.New.Name} 增加了 {increase.New.Performance - increase.Old.Performance:#.##} PP。") sb.Append(increase.New.Name).Append(" 增加了 ").AppendFormat("{0:#.##}", increase.New.Performance - increase.Old.Performance).AppendLine(" PP。") // .AppendLine($"({increase.Old.Performance:#.##} -> {increase.New.Performance:#.##})"); .Append('(').AppendFormat("{0:#.##}", increase.Old.Performance).Append(" -> ").AppendFormat("{0:#.##}", increase.New.Performance).AppendLine(")"); } else { sb.AppendLine("你群没有人飞升。"); } sb.AppendLine("最肝:") // .Append($"{mostPlay.New.Name} 打了 {mostPlay.New.TotalHits - mostPlay.Old.TotalHits} 下。"); .Append(mostPlay.New.Name).Append(" 打了 ").Append(mostPlay.New.TotalHits - mostPlay.Old.TotalHits).Append(" 下。"); await api.SendMessageAsync(context.Endpoint, sb.ToString()); } } }
public Recommand(IOsuApiClient osuApiClient, NewbieContext newbieContext) { _osuApiClient = osuApiClient; _newbieContext = newbieContext; }
public QueryHelper(IOsuApiClient osuApi, NewbieContext newbieContext) { _osuApi = osuApi; _newbieContext = newbieContext; }
public Clear(NewbieContext newbieContext) { _newbieContext = newbieContext; }
public MyYearly(IDataProvider dataProvider, IOsuApiClient osuApiClient, NewbieContext newbieContext) { _dataProvider = dataProvider; _osuApiClient = osuApiClient; _newbieContext = newbieContext; }