答案 0 :(得分:5)
由于您使用实体框架标记了问题,我假设您要在数据层或接近数据库中执行此操作。有很多方法可以做到这一点。
您可以在上下文中覆盖SaveChanges()
。这会将逻辑移离模型,但仍可确保保存正确的值。此外,如果您想在多个实体上使用它,您可以使用界面。当它是interface
时,您可以为几个实体执行此操作而不需要任何重复代码,只要它是相同的属性即可。否则你需要一个属性和反射。可重用性非常高,但它会为您的SaveChanges()
增加一些开销。
public class CustomerEntity()
{
public string Name {get;set;}
}
public MyCustomContext : DbContext
{
// Other stuff...
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<CustomerEntity>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
// Possibly check for null or if it's changed at all.
entry.Entity.Name = entry.Entity.Name.ToUpper();
}
}
return base.SaveChanges();
}
}
使用界面:
public interface INameIsAlwaysUpperCase
{
string Name {get;set;}
}
public MyCustomContext : DbContext
{
// Other stuff...
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<INameIsAlwaysUpperCase>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
// Possibly check for null or if it's changed at all.
entry.Entity.Name = entry.Entity.Name.ToUpper();
}
}
return base.SaveChanges();
}
}
您可以添加自定义验证。如果未正确保存,则会抛出异常。这样您就可以将责任转移给模型的消费者。但是,根据您的方案,您可能不想抛出异常。这是我的最爱,因为它迫使消费者以正确的方式来做这件事。根据评论,为什么抛出你可以默默地转换它?是的,这是一个有效的问题。对我来说,它是强迫数据层的消费者正确使用它,而不是让daya层决定数据的用途。当业务层要求数据层保存一件事时,我个人不喜欢它,然后数据层保存了另一件事。如果小写不是有效选项,则不应保存。我不认为它与使用[Required]
更加不同。但它真的是关于背景以及在你的特定情况下有效的方法。
public class CustomerEntity() : IValidatableObject
{
public string Name {get;set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// Possibly check for null here as well...
if (this.Name.ToUpper() != this.Name)
{
yield return new ValidationResult("You need to save as upper!");
}
}
}
使用管理此功能的属性。这可能是最简单的解决方案,即使我希望保持我的实体“干净”。绝对是需要最少努力的解决方案。但是,可重用性很低,如果您在整个应用程序中使用自己的权限并希望将值设置为小写,直到实际保存为止,该怎么办?那是不可能的。但是,再次,我认为这取决于您的具体情况。如果您希望在保存它之前将值设置为大写 ,这可能是最好的解决方案!
public class CustomerEntity()
{
string _name;
public string Name
{
get { return _name; }
set { _name = value.ToUpper(); } // Check for null ?
}
}
保存时执行此操作。这会将逻辑移至您保存实体时。这可能是最不可取的选择,因为可重用性不存在。 Update()
会发生什么?但是,OP明确指出“当我添加新行时,因此它可能仅在添加新实体时适用。在这种情况下,它很可能是最受欢迎的选择,因为它允许更新具有小写。但它必须依赖于用例。
public void AddCustomer(string name)
{
var customer = new CustomerEntity
{
Name = name.ToUpper()
};
_context.Customers.Add(customer);
}
答案 1 :(得分:1)
只需使用属性。如果您的模型如下:
public class MyModel
{
public int Id { get; set; }
public string Description { get; set; }
public string LanguageCode { get; set; }
public string FiledName { get; set; }
}
然后,将其更改为:
public class MyModel
{
private string fieldName;
public int Id { get; set; }
public string Description { get; set; }
public string LanguageCode { get; set; }
public string FiledName
{
get { return filedName; }
set
{
if(!string.IsNullOrEmpty(value))
fieldName = value.ToUpper();
else
fieldName = value;
}
}
}
答案 2 :(得分:0)
尝试一下。
public string FiledName
{
get { return filedName; }
set
{
filedName = !string.IsNullOrEmpty( value ) ? value.ToUpper() : value;
}
}
答案 3 :(得分:0)
也可以使用自定义属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Standardized : Attribute
{}
然后在你的模型中装饰属性:
public class MyModel
{
public string Id{ get; set; }
[Required]
[Standardized]
public string Description { get; set; }
}
取自@smoksnes 接受的答案,在您的 DbContext 类中,覆盖 SaveChanges()
, SaveChangesAsync()
(EF Core 5.x) 并使用反射添加私有方法以获取装饰属性并应用转换,例如这:
public override int SaveChanges()
{
StandardizeBeforeSaving();
return base.SaveChanges();
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
StandardizeBeforeSaving();
return await base.SaveChangesAsync(cancellationToken);
}
private void StandardizeBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
var properties = entry.Entity
.GetType()
.GetProperties()
.Where(prop => Attribute.IsDefined(prop, typeof(Standardized)) && prop.PropertyType == typeof(string));
foreach (var property in properties)
{
var value = entry.CurrentValues[property.Name]?.ToString() ?? string.Empty;
entry.CurrentValues[property.Name] = value.Standardize();
}
}
}
}
请注意,反射可能比已接受的答案中提供的其他技术慢。但对于大多数情况(即用户更新或创建几个属性不多的实体)应该没问题。