/// <summary> /// Configure context options<br/> /// 配置上下文选项<br/> /// </summary> /// <param name="optionsBuilder">Options builder</param> protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var pathConfig = Application.Ioc.Resolve <LocalPathConfig>(); if (string.Compare(DatabaseName, "MSSQL", true) == 0) { optionsBuilder.UseSqlServer( ConnectionString, option => option.UseRowNumberForPaging()); } else if (string.Compare(DatabaseName, "SQLite", true) == 0) { optionsBuilder.UseSqlite( ConnectionString.Replace("{{App_Data}}", pathConfig.AppDataDirectory)); } else if (string.Compare(DatabaseName, "MySQL", true) == 0) { optionsBuilder.UseMySql(ConnectionString); } else if (string.Compare(DatabaseName, "PostgreSQL", true) == 0) { optionsBuilder.UseNpgsql(ConnectionString); } else if (string.Compare(DatabaseName, "InMemory", true) == 0) { optionsBuilder.UseInMemoryDatabase( string.IsNullOrEmpty(ConnectionString) ? GuidUtils.SequentialGuid(DateTime.UtcNow).ToString() : ConnectionString); } else { throw new ArgumentException($"unsupported database type {Database}"); } // EF 2.0 make some warnings as error, just ignore them optionsBuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.IncludeIgnoredWarning)); }
public void SequentialGuid() { var a = GuidUtils.SequentialGuid(new DateTime(2016, 8, 8)); var b = GuidUtils.SequentialGuid(new DateTime(2016, 8, 9)); Assert.IsTrue(a != Guid.Empty); Assert.IsTrue(b != Guid.Empty); Assert.IsTrueWith(string.Compare(a.ToString(), b.ToString()) < 0, new { a, b }); }
/// <summary> /// 自动设置Guid主键值 /// </summary> void IEntityOperationFilter.FilterSave <TEntity, TPrimaryKey>(TEntity entity) { if (typeof(TPrimaryKey) == typeof(Guid)) { var eg = (IEntity <Guid>)entity; if (eg.Id == Guid.Empty) { // 主键是空时自动生成主键 eg.Id = GuidUtils.SequentialGuid(DateTime.UtcNow); } } }
/// <summary> /// Configure context options<br/> /// 配置上下文选项<br/> /// </summary> /// <param name="optionsBuilder">Options builder</param> protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var pathConfig = Application.Ioc.Resolve <LocalPathConfig>(); if (string.Compare(DatabaseName, "MSSQL", true, CultureInfo.InvariantCulture) == 0) { optionsBuilder.UseSqlServer( ConnectionString, option => option.UseRowNumberForPaging()); } else if (string.Compare(DatabaseName, "SQLite", true, CultureInfo.InvariantCulture) == 0) { optionsBuilder.UseSqlite( ConnectionString.Replace("{{App_Data}}", pathConfig.AppDataDirectory)); } else if (string.Compare(DatabaseName, "MySQL", true, CultureInfo.InvariantCulture) == 0) { optionsBuilder.UseMySql(ConnectionString); } else if (string.Compare(DatabaseName, "PostgreSQL", true, CultureInfo.InvariantCulture) == 0) { optionsBuilder.UseNpgsql(ConnectionString); } else if (string.Compare(DatabaseName, "InMemory", true, CultureInfo.InvariantCulture) == 0) { optionsBuilder.UseInMemoryDatabase( string.IsNullOrEmpty(ConnectionString) ? GuidUtils.SequentialGuid(DateTime.UtcNow).ToString() : ConnectionString); } else { throw new ArgumentException($"unsupported database type {Database}"); } // EF 2.0 make some warnings as error, just ignore them // EF 3.0 obsolete IncludeIgnoredWarning without any comment and description, wtf? #pragma warning disable CS0612 optionsBuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.IncludeIgnoredWarning)); #pragma warning restore CS0612 // Allow logging sql parameters optionsBuilder.EnableSensitiveDataLogging(); // Enable lazy loading (exclude .NET Core 3.0) // On .NET Core 3.0 you will see this error: // A non-collectible assembly may not reference a collectible assembly // See this issue: // https://github.com/aspnet/EntityFrameworkCore/issues/18272 if (!Application.Unloadable) { optionsBuilder.UseLazyLoadingProxies(); } }
/// <summary> /// 转换到数据库使用的集合 /// </summary> /// <param name="values">编辑后的商品属性对应的属性值列表</param> /// <param name="property">商品属性</param> /// <returns></returns> public static ISet <ProductPropertyValue> ToDatabaseSet( this IList <ProductPropertyValueForEdit> values, ProductProperty property) { if (values == null) { return(new HashSet <ProductPropertyValue>()); } var set = property.PropertyValues ?? new HashSet <ProductPropertyValue>(); var addValues = new List <ProductPropertyValue>(); var now = DateTime.UtcNow; for (int i = 0; i < values.Count; ++i) { var value = values[i]; if (value.Id == null) { // 添加属性值(临时) addValues.Add(new ProductPropertyValue() { Id = GuidUtils.SequentialGuid(now), Name = value.Name, Property = property, DisplayOrder = i, CreateTime = now, UpdateTime = now, Remark = value.Remark }); } else { // 更新属性值 var updateValue = set.First(p => p.Id == value.Id); updateValue.Name = value.Name; updateValue.DisplayOrder = i; updateValue.UpdateTime = now; updateValue.Remark = value.Remark; } } // 删除属性值 var aliveIds = new HashSet <Guid>(values.Where(v => v.Id != null).Select(v => v.Id.Value)); var deleteValues = set.Where(p => !aliveIds.Contains(p.Id)).ToList(); deleteValues.ForEach(v => set.Remove(v)); // 添加属性值 addValues.ForEach(v => set.Add(v)); return(set); }
/// <summary> /// If an entity have a integer or guid primary key, and it's empty,<br/> /// then generate a new primary key for it.<br/> /// Return the final primary key.<br/> /// 如果实体有一个数值或者guid主键, 并且主键为空<br/> /// 则生成一个新的主键<br/> /// 返回最终的主键<br/> /// </summary> public object EnsurePrimaryKey <T>(T entity) { var mapping = Mappings[typeof(T)]; var primaryKey = GetPrimaryKey(entity); if ((primaryKey is int || primaryKey is long) && ((long)primaryKey) <= 0) { lock (PrimaryKeySequenceLock) { primaryKey = PrimaryKeySequence.GetOrAdd(typeof(T), 0) + 1; PrimaryKeySequence[typeof(T)] = (long)primaryKey; } mapping.IdMember.FastSetValue(entity, primaryKey); } else if (primaryKey is Guid && (Guid)primaryKey == Guid.Empty) { primaryKey = GuidUtils.SequentialGuid(DateTime.UtcNow); mapping.IdMember.FastSetValue(entity, primaryKey); } return(primaryKey); }
/// <summary> /// 按卖家分别创建订单 /// </summary> protected virtual void CreateOrdersBySellers() { var orderManager = Application.Ioc.Resolve <SellerOrderManager>(); var userManager = Application.Ioc.Resolve <UserManager>(); var productManager = Application.Ioc.Resolve <ProductManager>(); var buyerOrderManager = Application.Ioc.Resolve <BuyerOrderManager>(); var transactionManager = Application.Ioc.Resolve <PaymentTransactionManager>(); var products = new Dictionary <Guid, Product>(); var groupedProductParameters = Parameters.OrderProductParametersList.Select(p => new { productParameters = p, product = products.GetOrCreate(p.ProductId, () => productManager.Get(p.ProductId)) }).GroupBy(p => p.product.Seller?.Id).ToList(); // { 卖家: [ (参数, 商品) ] } var now = DateTime.UtcNow; foreach (var group in groupedProductParameters) { // 计算订单的价格 // 支付手续费需要单独提取出来 var orderPrice = orderManager.CalculateOrderPrice( Parameters.CloneWith(group.Select(o => o.productParameters).ToList())); var paymentFee = orderPrice.Parts.FirstOrDefault(p => p.Type == "PaymentFee"); orderPrice.Parts.Remove(paymentFee); // 生成卖家订单 var sellerOrder = new SellerOrder() { Buyer = Parameters.UserId == null ? null : userManager.Get(Parameters.UserId.Value), Owner = (group.Key == null) ? null : userManager.Get(group.Key.Value), State = OrderState.WaitingBuyerPay, OrderParameters = Parameters.OrderParameters, TotalCost = orderPrice.Parts.Sum(), Currency = orderPrice.Currency, TotalCostCalcResult = orderPrice, OriginalTotalCostCalcResult = orderPrice, StateTimes = new OrderStateTimes() { { OrderState.WaitingBuyerPay, now } } }; // 添加关联的订单商品 // 这里会重新计算单价,但应该和之前的计算结果一样 foreach (var obj in group) { var unitPrice = orderManager.CalculateOrderProductUnitPrice( Parameters.UserId, obj.productParameters); var orderCount = obj.productParameters.MatchParameters.GetOrderCount(); var properties = obj.productParameters.MatchParameters.GetProperties(); var orderProduct = new OrderProduct() { Id = GuidUtils.SequentialGuid(now), Order = sellerOrder, Product = obj.product, MatchParameters = obj.productParameters.MatchParameters, Count = orderCount, UnitPrice = unitPrice.Parts.Sum(), Currency = unitPrice.Currency, UnitPriceCalcResult = unitPrice, OriginalUnitPriceCalcResult = unitPrice, CreateTime = now, UpdateTime = now }; // 添加关联的属性 foreach (var productToPropertyValue in obj.product .FindPropertyValuesFromPropertyParameters(properties)) { orderProduct.PropertyValues.Add(new OrderProductToPropertyValue() { Id = GuidUtils.SequentialGuid(now), OrderProduct = orderProduct, Category = obj.product.Category, Property = productToPropertyValue.Property, PropertyValue = productToPropertyValue.PropertyValue, PropertyValueName = productToPropertyValue.PropertyValueName }); } sellerOrder.OrderProducts.Add(orderProduct); } // 添加关联的订单留言 var comment = Parameters.OrderParameters.GetOrderComment(); if (!string.IsNullOrEmpty(comment)) { sellerOrder.OrderComments.Add(new OrderComment() { Id = GuidUtils.SequentialGuid(now), Order = sellerOrder, Owner = sellerOrder.Buyer, Side = OrderCommentSide.BuyerComment, Contents = comment, CreateTime = now, UpdateTime = now }); } // 生成订单编号 sellerOrder.Serial = SerialGenerator.GenerateFor(sellerOrder); // 保存卖家订单 orderManager.Save(ref sellerOrder); Result.CreatedSellerOrders.Add(sellerOrder); // 生成买家订单 var buyerOrder = new BuyerOrder() { Owner = sellerOrder.Buyer, SellerOrder = sellerOrder, BuyerSessionId = (sellerOrder.Buyer != null) ? null : (Guid?)Parameters.SessionId }; // 保存买家订单 buyerOrderManager.Save(ref buyerOrder); Result.CreatedBuyerOrders.Add(buyerOrder); // 创建订单交易 // 因为目前只能使用后台的支付接口,所以收款人应该是null var paymentApiId = Parameters.OrderParameters.GetPaymentApiId(); var transaction = transactionManager.CreateTransaction( OrderTransactionHandler.ConstType, paymentApiId, sellerOrder.TotalCost, paymentFee?.Delta ?? 0, sellerOrder.Currency, sellerOrder.Buyer?.Id, null, sellerOrder.Id, sellerOrder.Serial); Result.CreatedTransactions.Add(transaction); } }