C# 有没有比手工检查每个属性更有效的合并模型的方法?
我正在构建一个API,在这个API中,如果调用方在HTTP调用的主体中包含了某些属性,我只想发送这些属性的更新 我目前正在做以下工作。。但它看起来很笨重。有没有更简单的方法C# 有没有比手工检查每个属性更有效的合并模型的方法?,c#,C#,我正在构建一个API,在这个API中,如果调用方在HTTP调用的主体中包含了某些属性,我只想发送这些属性的更新 我目前正在做以下工作。。但它看起来很笨重。有没有更简单的方法 public void MergePerson(Person basePerson, Person updatedPerson) { if (updatedPerson.Title != null) basePerson.Title = updatedPerson.Ti
public void MergePerson(Person basePerson, Person updatedPerson)
{
if (updatedPerson.Title != null)
basePerson.Title = updatedPerson.Title;
if (updatedPerson.Initials != null)
basePerson.Initials = updatedPerson.Initials;
if (updatedPerson.FirstName != null)
basePerson.FirstName = updatedPerson.FirstName;
if (updatedPerson.LastName != null)
basePerson.LastName = updatedPerson.LastName;
if (updatedPerson.Sex != null)
basePerson.Sex = updatedPerson.Sex;
if (updatedPerson.DateOfBirth != null)
basePerson.DateOfBirth = updatedPerson.DateOfBirth;
if (updatedPerson.JobTitle != null)
basePerson.JobTitle = updatedPerson.JobTitle;
<<< snip >>>
public void MergePerson(Person-basePerson,Person-updatedPerson)
{
if(updatedPerson.Title!=null)
basePerson.Title=updatedPerson.Title;
if(updatedPerson.Initials!=null)
basePerson.Initials=updatedPerson.Initials;
if(updatedPerson.FirstName!=null)
basePerson.FirstName=updatedPerson.FirstName;
if(updatedPerson.LastName!=null)
basePerson.LastName=updatedPerson.LastName;
if(updatedPerson.Sex!=null)
basePerson.Sex=更新的Person.Sex;
if(updatedPerson.DateOfBirth!=null)
basePerson.DateOfBirth=updatedPerson.DateOfBirth;
if(updatedPerson.JobTitle!=null)
basePerson.JobTitle=updatedPerson.JobTitle;
>
由于这个原因,我不得不将bools设置为non-nullable,这样我就可以确认它们实际上是被传递的,而不是仅仅设置为默认值false
我担心的是,有一天我会向模型中添加新字段,而忘了在此处添加它们。您要做的是称为补丁 检查此代码
public class Car
{
public int Id { get; set; }
[Required]
[StringLength(20)]
public string Make { get; set; }
[Required]
[StringLength(20)]
public string Model { get; set; }
public int Year { get; set; }
[Range(0, 500000)]
public float Price { get; set; }
}
public class CarPatch
{
[StringLength(20)]
public string Make { get; set; }
[StringLength(20)]
public string Model { get; set; }
public int? Year { get; set; }
[Range(0, 500000)]
public float? Price { get; set; }
}
public class CarsController : ApiController
{
private readonly CarsContext _carsCtx = new CarsContext();
// PATCH /api/cars/{id}
public Car PatchCar(int id, CarPatch car)
{
var carTuple = _carsCtx.GetSingle(id);
if (!carTuple.Item1)
{
var response = Request.CreateResponse(HttpStatusCode.NotFound);
throw new HttpResponseException(response);
}
Patch<CarPatch, Car>(car, carTuple.Item2);
// Not required but better to put here to simulate the external storage.
if (!_carsCtx.TryUpdate(carTuple.Item2))
{
var response = Request.CreateResponse(HttpStatusCode.NotFound);
throw new HttpResponseException(response);
}
return carTuple.Item2;
}
// private helpers
private static ConcurrentDictionary<Type, PropertyInfo[]> TypePropertiesCache =
new ConcurrentDictionary<Type, PropertyInfo[]>();
private void Patch<TPatch, TEntity>(TPatch patch, TEntity entity)
where TPatch : class
where TEntity : class
{
PropertyInfo[] properties = TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type) => type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach (PropertyInfo prop in properties)
{
PropertyInfo orjProp = entity.GetType().GetProperty(prop.Name);
object value = prop.GetValue(patch);
if (value != null)
{
orjProp.SetValue(entity, value);
}
}
}
}
公车
{
公共int Id{get;set;}
[必需]
[行政长官(20)]
公共字符串Make{get;set;}
[必需]
[行政长官(20)]
公共字符串模型{get;set;}
公共整数年{get;set;}
[范围(0,500000)]
公开浮动价格{get;set;}
}
公共级停车场
{
[行政长官(20)]
公共字符串Make{get;set;}
[行政长官(20)]
公共字符串模型{get;set;}
公共整数?年份{get;set;}
[范围(0,500000)]
公开浮动?价格{get;set;}
}
公共类车辆控制器:ApiController
{
私有只读CarsContext_carsCtx=new CarsContext();
//补丁/api/cars/{id}
公共汽车修补车(内部id,汽车修补车)
{
var carTuple=\u carsCtx.GetSingle(id);
如果(!carTuple.Item1)
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
补丁(car,carTuple.Item2);
//不需要,但最好放在这里模拟外部存储。
如果(!\u carsCtx.TryUpdate(carTuple.Item2))
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
返回carTuple.Item2;
}
//私人佣工
私有静态ConcurrentDictionary类型属性缓存=
新的ConcurrentDictionary();
专用无效补丁(TPatch补丁、TEntity实体)
TPatch的位置:类
地点:班级
{
PropertyInfo[]properties=TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type)=>type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach(PropertyInfo属性中的属性)
{
PropertyInfo或jprop=entity.GetType().GetProperty(prop.Name);
对象值=prop.GetValue(面片);
if(值!=null)
{
orjProp.SetValue(实体,值);
}
}
}
}
您要做的是称为补丁 检查此代码
public class Car
{
public int Id { get; set; }
[Required]
[StringLength(20)]
public string Make { get; set; }
[Required]
[StringLength(20)]
public string Model { get; set; }
public int Year { get; set; }
[Range(0, 500000)]
public float Price { get; set; }
}
public class CarPatch
{
[StringLength(20)]
public string Make { get; set; }
[StringLength(20)]
public string Model { get; set; }
public int? Year { get; set; }
[Range(0, 500000)]
public float? Price { get; set; }
}
public class CarsController : ApiController
{
private readonly CarsContext _carsCtx = new CarsContext();
// PATCH /api/cars/{id}
public Car PatchCar(int id, CarPatch car)
{
var carTuple = _carsCtx.GetSingle(id);
if (!carTuple.Item1)
{
var response = Request.CreateResponse(HttpStatusCode.NotFound);
throw new HttpResponseException(response);
}
Patch<CarPatch, Car>(car, carTuple.Item2);
// Not required but better to put here to simulate the external storage.
if (!_carsCtx.TryUpdate(carTuple.Item2))
{
var response = Request.CreateResponse(HttpStatusCode.NotFound);
throw new HttpResponseException(response);
}
return carTuple.Item2;
}
// private helpers
private static ConcurrentDictionary<Type, PropertyInfo[]> TypePropertiesCache =
new ConcurrentDictionary<Type, PropertyInfo[]>();
private void Patch<TPatch, TEntity>(TPatch patch, TEntity entity)
where TPatch : class
where TEntity : class
{
PropertyInfo[] properties = TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type) => type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach (PropertyInfo prop in properties)
{
PropertyInfo orjProp = entity.GetType().GetProperty(prop.Name);
object value = prop.GetValue(patch);
if (value != null)
{
orjProp.SetValue(entity, value);
}
}
}
}
公车
{
公共int Id{get;set;}
[必需]
[行政长官(20)]
公共字符串Make{get;set;}
[必需]
[行政长官(20)]
公共字符串模型{get;set;}
公共整数年{get;set;}
[范围(0,500000)]
公开浮动价格{get;set;}
}
公共级停车场
{
[行政长官(20)]
公共字符串Make{get;set;}
[行政长官(20)]
公共字符串模型{get;set;}
公共整数?年份{get;set;}
[范围(0,500000)]
公开浮动?价格{get;set;}
}
公共类车辆控制器:ApiController
{
私有只读CarsContext_carsCtx=new CarsContext();
//补丁/api/cars/{id}
公共汽车修补车(内部id,汽车修补车)
{
var carTuple=\u carsCtx.GetSingle(id);
如果(!carTuple.Item1)
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
补丁(car,carTuple.Item2);
//不需要,但最好放在这里模拟外部存储。
如果(!\u carsCtx.TryUpdate(carTuple.Item2))
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
返回carTuple.Item2;
}
//私人佣工
私有静态ConcurrentDictionary类型属性缓存=
新的ConcurrentDictionary();
专用无效补丁(TPatch补丁、TEntity实体)
TPatch的位置:类
地点:班级
{
PropertyInfo[]properties=TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type)=>type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach(PropertyInfo属性中的属性)
{
PropertyInfo或jprop=entity.GetType().GetProperty(prop.Name);
对象值=prop.GetValue(面片);
if(值!=null)
{
orjProp.SetValue(实体,值);
}
}
}
}
通过反射,您可以轻松做到这一点:
public static void MapPersons(object basePerson, object updatedPerson)
{
var sourceT = basePerson.GetType();
var sourceProps = sourceT.GetProperties();
var targetT = updatedPerson.GetType();
var targetProps = targetT.GetProperties();
foreach (var sProp in sourceProps)
{
var sourceValue = sProp.GetValue(basePerson, null);
var propIndex = Array.IndexOf(targetProps, sProp);
if (propIndex != -1)
{
var tProp = targetProps[propIndex];
tProp.SetValue(updatedPerson, sourceValue);
}
}
}
但这里有很多功能强大的工具,例如。它们将为您处理这些问题。您可以通过反射轻松实现这一点:
public static void MapPersons(object basePerson, object updatedPerson)
{
var sourceT = basePerson.GetType();
var sourceProps = sourceT.GetProperties();
var targetT = updatedPerson.GetType();
var targetProps = targetT.GetProperties();
foreach (var sProp in sourceProps)
{
var sourceValue = sProp.GetValue(basePerson, null);
var propIndex = Array.IndexOf(targetProps, sProp);
if (propIndex != -1)
{
var tProp = targetProps[propIndex];
tProp.SetValue(updatedPerson, sourceValue);
}
}
}
但是这里有很多功能强大的工具,比如。它们会为您处理这些问题。不知道更简单,但是一行应该是
basePerson.Title=updatedPerson.Title!=null?updatedPerson.Title:“否则”
等等(用您想要的默认值替换为“否则”)。谢谢..但我不想要“否则”第……Y节