594 lines
20 KiB
C#
594 lines
20 KiB
C#
using FsCheck;
|
||
using FsCheck.Xunit;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
using MiAssessment.Core.Services;
|
||
using MiAssessment.Model.Data;
|
||
using MiAssessment.Model.Entities;
|
||
using Moq;
|
||
using Xunit;
|
||
|
||
namespace MiAssessment.Tests.Services;
|
||
|
||
/// <summary>
|
||
/// HomeService 属性测试
|
||
/// 验证首页服务的列表查询过滤和排序正确性
|
||
/// </summary>
|
||
public class HomeServicePropertyTests
|
||
{
|
||
private readonly Mock<ILogger<HomeService>> _mockLogger = new();
|
||
|
||
#region Property 1: 列表查询过滤正确性 - Banner
|
||
|
||
/// <summary>
|
||
/// Property 1: Banner列表只返回启用状态的记录
|
||
/// *For any* Banner list query, the returned items SHALL only include records
|
||
/// with Status=1 and IsDeleted=false.
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool BannerListOnlyReturnsEnabledRecords(PositiveInt seed)
|
||
{
|
||
// Arrange: 创建包含不同状态的Banner数据
|
||
using var dbContext = CreateDbContext();
|
||
var random = new Random(seed.Get);
|
||
|
||
// 创建启用的Banner
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
dbContext.Banners.Add(CreateBanner(seed.Get + i, status: 1, isDeleted: false));
|
||
}
|
||
|
||
// 创建禁用的Banner
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
dbContext.Banners.Add(CreateBanner(seed.Get + 100 + i, status: 0, isDeleted: false));
|
||
}
|
||
|
||
// 创建已删除的Banner
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
dbContext.Banners.Add(CreateBanner(seed.Get + 200 + i, status: 1, isDeleted: true));
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act: 调用服务方法
|
||
var result = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 验证返回结果只包含Status=1且未删除的记录
|
||
// 1. 返回的记录数应该等于启用且未删除的记录数
|
||
if (result.Count != 3) return false;
|
||
|
||
// 2. 验证数据库中确实存在被过滤掉的记录
|
||
var allBanners = dbContext.Banners.ToList();
|
||
var disabledBanners = allBanners.Where(b => b.Status == 0 && !b.IsDeleted).ToList();
|
||
var deletedBanners = allBanners.Where(b => b.IsDeleted).ToList();
|
||
|
||
if (disabledBanners.Count != 2 || deletedBanners.Count != 2) return false;
|
||
|
||
// 3. 验证返回的记录中不包含禁用或已删除的记录
|
||
var returnedIds = result.Select(b => b.Id).ToHashSet();
|
||
var disabledIds = disabledBanners.Select(b => b.Id).ToHashSet();
|
||
var deletedIds = deletedBanners.Select(b => b.Id).ToHashSet();
|
||
|
||
return !returnedIds.Intersect(disabledIds).Any() && !returnedIds.Intersect(deletedIds).Any();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Property 1: Banner列表不返回已删除的记录
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool BannerListExcludesDeletedRecords(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建一些启用的Banner
|
||
var activeBanner = CreateBanner(seed.Get, status: 1, isDeleted: false);
|
||
dbContext.Banners.Add(activeBanner);
|
||
|
||
// 创建已删除的Banner(即使Status=1)
|
||
var deletedBanner = CreateBanner(seed.Get + 1, status: 1, isDeleted: true);
|
||
dbContext.Banners.Add(deletedBanner);
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 已删除的记录不应出现在结果中
|
||
return result.Count == 1 && result[0].Id == activeBanner.Id;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 1: 列表查询过滤正确性 - AssessmentType
|
||
|
||
/// <summary>
|
||
/// Property 1: 测评类型列表只返回未删除的记录
|
||
/// *For any* AssessmentType list query, the returned items SHALL only include
|
||
/// records with IsDeleted=false.
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.2**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool AssessmentTypeListOnlyReturnsNonDeletedRecords(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建未删除的测评类型(包含不同状态)
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
dbContext.AssessmentTypes.Add(CreateAssessmentType(seed.Get + i, status: i, isDeleted: false));
|
||
}
|
||
|
||
// 创建已删除的测评类型
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
dbContext.AssessmentTypes.Add(CreateAssessmentType(seed.Get + 100 + i, status: 1, isDeleted: true));
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetAssessmentListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 返回的记录数应该等于未删除的记录数
|
||
if (result.Count != 3) return false;
|
||
|
||
// 验证返回的记录中不包含已删除的记录
|
||
var allTypes = dbContext.AssessmentTypes.ToList();
|
||
var deletedTypes = allTypes.Where(a => a.IsDeleted).ToList();
|
||
var returnedIds = result.Select(a => a.Id).ToHashSet();
|
||
var deletedIds = deletedTypes.Select(a => a.Id).ToHashSet();
|
||
|
||
return !returnedIds.Intersect(deletedIds).Any();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Property 1: 测评类型列表包含所有状态的未删除记录
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.2**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool AssessmentTypeListIncludesAllStatusRecords(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建不同状态的测评类型:0已下线 1已上线 2即将上线
|
||
var offlineType = CreateAssessmentType(seed.Get, status: 0, isDeleted: false);
|
||
var onlineType = CreateAssessmentType(seed.Get + 1, status: 1, isDeleted: false);
|
||
var comingSoonType = CreateAssessmentType(seed.Get + 2, status: 2, isDeleted: false);
|
||
|
||
dbContext.AssessmentTypes.AddRange(offlineType, onlineType, comingSoonType);
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetAssessmentListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 应该返回所有未删除的记录,不管状态如何
|
||
var returnedIds = result.Select(a => a.Id).ToHashSet();
|
||
return returnedIds.Contains(offlineType.Id)
|
||
&& returnedIds.Contains(onlineType.Id)
|
||
&& returnedIds.Contains(comingSoonType.Id);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 1: 列表查询过滤正确性 - Promotion
|
||
|
||
/// <summary>
|
||
/// Property 1: 宣传图列表只返回首页位置且启用状态的记录
|
||
/// *For any* Promotion list query, the returned items SHALL only include records
|
||
/// with Position=1, Status=1, and IsDeleted=false.
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool PromotionListOnlyReturnsHomePageEnabledRecords(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建首页位置且启用的宣传图
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + i, position: 1, status: 1, isDeleted: false));
|
||
}
|
||
|
||
// 创建团队页位置的宣传图(Position=2)
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + 100 + i, position: 2, status: 1, isDeleted: false));
|
||
}
|
||
|
||
// 创建首页位置但禁用的宣传图
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + 200, position: 1, status: 0, isDeleted: false));
|
||
|
||
// 创建首页位置但已删除的宣传图
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + 300, position: 1, status: 1, isDeleted: true));
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetPromotionListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 返回的记录数应该等于首页位置且启用且未删除的记录数
|
||
if (result.Count != 2) return false;
|
||
|
||
// 验证返回的记录中不包含其他位置、禁用或已删除的记录
|
||
var allPromotions = dbContext.Promotions.ToList();
|
||
var excludedPromotions = allPromotions.Where(p => p.Position != 1 || p.Status != 1 || p.IsDeleted).ToList();
|
||
var returnedIds = result.Select(p => p.Id).ToHashSet();
|
||
var excludedIds = excludedPromotions.Select(p => p.Id).ToHashSet();
|
||
|
||
return !returnedIds.Intersect(excludedIds).Any();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Property 1: 宣传图列表不返回团队页位置的记录
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool PromotionListExcludesTeamPageRecords(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建首页位置的宣传图
|
||
var homePromotion = CreatePromotion(seed.Get, position: 1, status: 1, isDeleted: false);
|
||
dbContext.Promotions.Add(homePromotion);
|
||
|
||
// 创建团队页位置的宣传图
|
||
var teamPromotion = CreatePromotion(seed.Get + 1, position: 2, status: 1, isDeleted: false);
|
||
dbContext.Promotions.Add(teamPromotion);
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetPromotionListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 只返回首页位置的记录
|
||
return result.Count == 1 && result[0].Id == homePromotion.Id;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 2: 列表查询排序正确性 - Banner
|
||
|
||
/// <summary>
|
||
/// Property 2: Banner列表按Sort字段降序排列
|
||
/// *For any* Banner list query, the returned items SHALL be ordered by Sort
|
||
/// field in descending order.
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool BannerListSortedBySortDescending(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
var random = new Random(seed.Get);
|
||
|
||
// 创建具有不同Sort值的Banner
|
||
var sortValues = new List<int>();
|
||
for (int i = 0; i < 5; i++)
|
||
{
|
||
var sortValue = random.Next(1, 1000);
|
||
sortValues.Add(sortValue);
|
||
dbContext.Banners.Add(CreateBannerWithSort(seed.Get + i, sortValue));
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 验证列表按Sort降序排列
|
||
if (result.Count < 2) return true;
|
||
|
||
for (int i = 0; i < result.Count - 1; i++)
|
||
{
|
||
// 获取当前和下一个Banner的Sort值
|
||
var currentBanner = dbContext.Banners.First(b => b.Id == result[i].Id);
|
||
var nextBanner = dbContext.Banners.First(b => b.Id == result[i + 1].Id);
|
||
|
||
if (currentBanner.Sort < nextBanner.Sort)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Property 2: Banner列表排序稳定性
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1**
|
||
/// </summary>
|
||
[Property(MaxTest = 50)]
|
||
public bool BannerListSortingIsStable(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 创建具有相同Sort值的Banner
|
||
var sameSort = seed.Get % 100;
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
var banner = CreateBannerWithSort(seed.Get + i, sameSort);
|
||
dbContext.Banners.Add(banner);
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act: 多次调用应该返回相同的顺序
|
||
var result1 = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
var result2 = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 两次调用返回的顺序应该相同
|
||
if (result1.Count != result2.Count) return false;
|
||
|
||
for (int i = 0; i < result1.Count; i++)
|
||
{
|
||
if (result1[i].Id != result2[i].Id) return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 2: 列表查询排序正确性 - Promotion
|
||
|
||
/// <summary>
|
||
/// Property 2: 宣传图列表按Sort字段降序排列
|
||
/// *For any* Promotion list query, the returned items SHALL be ordered by Sort
|
||
/// field in descending order.
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool PromotionListSortedBySortDescending(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
var random = new Random(seed.Get);
|
||
|
||
// 创建具有不同Sort值的宣传图
|
||
for (int i = 0; i < 5; i++)
|
||
{
|
||
var sortValue = random.Next(1, 1000);
|
||
dbContext.Promotions.Add(CreatePromotionWithSort(seed.Get + i, sortValue));
|
||
}
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var result = service.GetPromotionListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 验证列表按Sort降序排列
|
||
if (result.Count < 2) return true;
|
||
|
||
for (int i = 0; i < result.Count - 1; i++)
|
||
{
|
||
var currentPromotion = dbContext.Promotions.First(p => p.Id == result[i].Id);
|
||
var nextPromotion = dbContext.Promotions.First(p => p.Id == result[i + 1].Id);
|
||
|
||
if (currentPromotion.Sort < nextPromotion.Sort)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 综合属性测试
|
||
|
||
/// <summary>
|
||
/// Property 1: 空数据库返回空列表
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1, 1.2, 1.3**
|
||
/// </summary>
|
||
[Fact]
|
||
public void EmptyDatabaseReturnsEmptyLists()
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var banners = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
var assessmentTypes = service.GetAssessmentListAsync().GetAwaiter().GetResult();
|
||
var promotions = service.GetPromotionListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert
|
||
Assert.Empty(banners);
|
||
Assert.Empty(assessmentTypes);
|
||
Assert.Empty(promotions);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Property 1: 所有记录都被过滤时返回空列表
|
||
///
|
||
/// **Feature: miniapp-api, Property 1: 列表查询过滤正确性**
|
||
/// **Validates: Requirements 1.1, 1.2, 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 50)]
|
||
public bool AllFilteredRecordsReturnsEmptyList(PositiveInt seed)
|
||
{
|
||
// Arrange
|
||
using var dbContext = CreateDbContext();
|
||
|
||
// 只创建不符合条件的记录
|
||
// Banner: 禁用或已删除
|
||
dbContext.Banners.Add(CreateBanner(seed.Get, status: 0, isDeleted: false));
|
||
dbContext.Banners.Add(CreateBanner(seed.Get + 1, status: 1, isDeleted: true));
|
||
|
||
// AssessmentType: 已删除
|
||
dbContext.AssessmentTypes.Add(CreateAssessmentType(seed.Get, status: 1, isDeleted: true));
|
||
|
||
// Promotion: 非首页位置、禁用或已删除
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get, position: 2, status: 1, isDeleted: false));
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + 1, position: 1, status: 0, isDeleted: false));
|
||
dbContext.Promotions.Add(CreatePromotion(seed.Get + 2, position: 1, status: 1, isDeleted: true));
|
||
|
||
dbContext.SaveChanges();
|
||
|
||
var service = new HomeService(dbContext, _mockLogger.Object);
|
||
|
||
// Act
|
||
var banners = service.GetBannerListAsync().GetAwaiter().GetResult();
|
||
var assessmentTypes = service.GetAssessmentListAsync().GetAwaiter().GetResult();
|
||
var promotions = service.GetPromotionListAsync().GetAwaiter().GetResult();
|
||
|
||
// Assert: 所有列表都应该为空
|
||
return banners.Count == 0 && assessmentTypes.Count == 0 && promotions.Count == 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 创建内存数据库上下文
|
||
/// </summary>
|
||
private MiAssessmentDbContext CreateDbContext()
|
||
{
|
||
var options = new DbContextOptionsBuilder<MiAssessmentDbContext>()
|
||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||
.Options;
|
||
|
||
return new MiAssessmentDbContext(options);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试Banner
|
||
/// </summary>
|
||
private Banner CreateBanner(int seed, int status, bool isDeleted)
|
||
{
|
||
return new Banner
|
||
{
|
||
Title = $"Test Banner {seed}",
|
||
ImageUrl = $"https://example.com/banner_{seed}.jpg",
|
||
LinkType = 0,
|
||
Sort = seed % 100,
|
||
Status = status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = isDeleted
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建指定Sort值的测试Banner
|
||
/// </summary>
|
||
private Banner CreateBannerWithSort(int seed, int sort)
|
||
{
|
||
return new Banner
|
||
{
|
||
Title = $"Test Banner {seed}",
|
||
ImageUrl = $"https://example.com/banner_{seed}.jpg",
|
||
LinkType = 0,
|
||
Sort = sort,
|
||
Status = 1,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试AssessmentType
|
||
/// </summary>
|
||
private AssessmentType CreateAssessmentType(int seed, int status, bool isDeleted)
|
||
{
|
||
return new AssessmentType
|
||
{
|
||
Name = $"Test Assessment {seed}",
|
||
Code = $"TEST_{seed}",
|
||
ImageUrl = $"https://example.com/assessment_{seed}.jpg",
|
||
Price = 99.00m,
|
||
Sort = seed % 100,
|
||
Status = status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = isDeleted
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试Promotion
|
||
/// </summary>
|
||
private Promotion CreatePromotion(int seed, int position, int status, bool isDeleted)
|
||
{
|
||
return new Promotion
|
||
{
|
||
Title = $"Test Promotion {seed}",
|
||
ImageUrl = $"https://example.com/promotion_{seed}.jpg",
|
||
Position = position,
|
||
Sort = seed % 100,
|
||
Status = status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = isDeleted
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建指定Sort值的测试Promotion
|
||
/// </summary>
|
||
private Promotion CreatePromotionWithSort(int seed, int sort)
|
||
{
|
||
return new Promotion
|
||
{
|
||
Title = $"Test Promotion {seed}",
|
||
ImageUrl = $"https://example.com/promotion_{seed}.jpg",
|
||
Position = 1,
|
||
Sort = sort,
|
||
Status = 1,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
}
|