c# - EF Core 5 DTO 映射规则和常规 CRUD 操作
问题描述
在一个大型项目中,我目前正在实现我的基础存储库和服务层。我不确定我目前正在做的事情是否矫枉过正(或者也许有更好/更简单的方法来做到这一点)。
这是我的情况:有些属性是用户永远无法更改的。因此,对于那些类型的属性,我相应地将映射规则设置为我的 DTO。但是,我不想将这些规则硬核到存储库中,因为这会使我在存储库层重复相同的规则,而且系统服务应该能够更改锁定的属性。
所以为了解决这个问题,我在上下文中禁用了延迟加载和代理创建,并在 Post-Sharp 中实现了一个轻量级的更改跟踪器。这是一个模型的例子。
[Tracking]
public class Currency: ModelBase
{
[Required]
[StringLength(20)]
public string Name { get; set; }
[Required]
[StringLength(10)]
public string Symbol { get; set; }
[Required]
[StringLength(10)]
public string Code { get; set; }
public string Comment { get; set; }
public string PrimaryAccount { get; set; }
public string SecondaryAccount { get; set; }
}
这是跟踪方面的实现。
[AttributeUsage(AttributeTargets.Class)]
[MulticastAttributeUsage(MulticastTargets.Property, TargetMemberAttributes = MulticastAttributes.Instance)]
[PSerializable]
public class TrackingAttribute : LocationInterceptionAspect
{
public override void OnSetValue(LocationInterceptionArgs args)
{
if(args.Instance is ITracking)
{
var model = (ITracking)args.Instance;
model.ChangedProperties.Add(args.Location.Name);
base.OnSetValue(args);
}
else
{
throw new IncorrectAttributeUsage("TracingAttribute can only be used on classes implementing ITracking interface.");
}
}
}
ModelBase
类似的东西在哪里
[Tracking]
public class ModelBase : ITracking
{
[NotMapped]
public HashSet<string> ChangedProperties { get; } = new HashSet<string>();
public int Id { get; set; }
[Required]
public DateTime CreateDate { get; set; } = DateTime.Now;
[Required]
public DateTime UpdateDate { get; set; } = DateTime.Now;
[Required]
public string CreatedBy { get; set; }
[Required]
}
例如在我的存储库中,我有如下方法:
public void UpdateEntity(T entity,string[] changedProperties, params Expression<Func<T, object>>[]ignoredProperties)
{
var entityEntry = db.Entry(entity);
entityEntry.State = EntityState.Modified;
var ignoredNames = new List<string>();
ignoredNames.Add(nameof(ModelBase.Id));
if (ignoredProperties != null && ignoredProperties.Length > 0)
{
foreach (var expression in ignoredProperties)
{
var propertyName = "";
propertyName = expression.GetMemberInfo().Member.Name;
ignoredNames.Add(propertyName);
}
}
var type = typeof(T);
var simpleProperties = type.GetProperties().Where(v => v.PropertyType.IsSimple() && !ignoredNames.Contains(v.Name));
var changedNames = entityEntry.Properties.Where(v => changedProperties?.Contains(v.Metadata.Name) != false && !ignoredNames.Contains(v.Metadata.Name)).Select(v=>v.Metadata.Name);
foreach (var prop in simpleProperties)
{
if (changedNames.Contains(prop.Name))
{
entityEntry.Property(prop.Name).IsModified = true;
}
else
{
entityEntry.Property(prop.Name).IsModified = false;
}
}
}
public async Task<T> UpdateChangedAsync(T entity)
{
UpdateEntity(entity,entity.ChangedProperties.ToArray());
return entity;
// return await UpdateChangedAsync(entity, null);
}
这是他们在服务中的用法
public async virtual Task<TDTO> UpdateAsync(TDTO entity)
{
var item = Mapper.Map<TEntity>(entity);
await Repository.UpdateChangedAsync(item);
await UnitOfWork.SaveChangesAsync();
return Mapper.Map<TDTO>(item);
}
这允许我只更新映射到项目的字段,而无需将任何逻辑或模型特定属性硬编码到存储库中。在一些小情况下,服务层中可能有几个。
我觉得可能有更好的方法来实现这一点,因为实施变更跟踪器并使用相当数量的反射感觉有点矫枉过正。然而,这是我处理过的最大的项目之一。当事情开始累加时,我真的不想重复任何逻辑不止一次它可能无法维护。
编辑:我不打算使用参考进行更新。我可能会用它们来添加对象。
解决方案
推荐阅读
- java - classLoader.getResources() 从 m2 包而不是我的目标包中选择资源。爪哇
- python - pygame set_alpha() 设置图像透明度的问题
- mysql - 通过使用下面提到的查询,我得到了错误的答案。有人可以解释为什么吗?
- asp.net-mvc - 无法在我的本地机器上安装 MVC 4.0 运行时
- report - Cognos Report Studio:如何根据查询输出更改显示的图像?
- coq - 将 ltac 应用于目标的子表达式
- spring - @Configuration 不应用取决于类的名称
- css - 通过 webpack 和 css 导入自定义字体的正确方法是什么?
- git - git push origin 的 TFS 远程消息
- javascript - Nest.js 如何将 Kafka 消费者与 WebSocket 一起使用