我有这个非常常见的问题。我有POCO人课。
[DataContract]
public class Person
{
[DataMember(IsRequired = true)]
public int id{get;set;}
[DataMember]
public decimal? Age{get;set;}
[DataMember]
public decimal? NumberOfChildren{get;set;}
}
我有WCF操作,这是
public class PersonManagerService
{ public void UpdatePerson(Person person)
{
//performs sql to update person in db
}
}
3)现在想象一下,在数据库中有一个id = 1,NumberOfChildren = 5和Age = 15的人事记录。
想象我有这样的客户端代码,在这种情况下我只想更新此人的年龄并保留所有其他字段。
Person p = new Person{id=1,Age=26;}
PersonManagerService service=new PersonManagerService();
service.UpdatePerson(p);
现在,一旦这段代码运行,我将遇到的问题是sql语句将运行并将NumberOfChildren更新为NULL。现在我知道我可以添加空检查以防止这是直截了当的。但是,我想要的是,在我指定字段具有空值的情况下,更新应设置为空值,如果未设置,则对该字段不执行任何操作。所以我在想的是我需要做这样的事情。创建一个具有此
的更新人员对象 [DataContract]
public class UpdatePerson
{
[DataMember(IsRequired = true)]
public int id{get;set;}
public bool IsAgeSpecified{get;set;}
[DataMember]
public decimal? Age{get;set;}
public bool IsNumberOfChildrenSpecified{get;set;}
[DataMember]
public decimal? NumberOfChildren{get;set;}
}
客户端代码现在就是
UpdatePerson p = new UpdatePerson{id=1,IsAgeSpecified=true,Age=26;}
PersonManagerService service=new PersonManagerService();
service.UpdatePerson(p);
我知道这会有效,但我不喜欢这种方法,因为你现在正在处理updatePerson而不是Person。有没有人建议更好的方法?
答案 0 :(得分:2)
您错过了识别某人的步骤。你在哪里想出id = 1?
例如:
PersonManagerService service=new PersonManagerService();
Person p = service.findPersonByNumberOfChildren(5);
p.Age = 26;
service.UpdatePerson(p);
答案 1 :(得分:2)
您可以让您的“UpdatePerson”类继承自“Person”。这样您就不必两次编写“Person”的定义。您仍然需要进行映射。不确定您是否使用AutoMapper或类似的东西,或者您只是手动编写映射。
[DataContract]
public class UpdatePerson : Person
{
[DataMember]
public bool IsAgeSpecified{get;set;}
[DataMember]
public bool IsNumberOfChildrenSpecified{get;set;}
}
答案 2 :(得分:1)
嗯..您的服务应该只公开客户端将使用的数据。然后,这些数据将一起更新。不确定这是否适用于您的场景,但我想知道您是否应该考虑将服务划分为更加面向客户需求。
例如,您可以考虑将“Person”划分为面向服务真正更新的表示类。但由于“Person”已经太小,在这种特殊情况下,您可以将属性打开为应该一起更新的参数。你可以得到这样的东西:
public class PersonManagerService
{ public void UpdatePerson(int personId, decimal age, decimal numberOfChildren);
{
//Instantiate new Person object filling the properties, say that age and numberOfChilren properties must be updated and call _UpdatePerson.
}
public void UpdatePerson(int personId, decimal age)
{
//Instantiate new Person object filling the age, say that age property must be updated and call _UpdatePerson.
}
public void UpdatePerson(decimal numberOfChildren, int personId)
{
//Instantiate new Person object filling the numberOfChildren, say that numberOfChilren property must be updated and call _UpdatePerson.
}
private void _UpdatePerson(Person person)
{
//do db stuffs
}
}
要说明应更新哪些属性,您可以执行类似context.Entry(youreEntity).Property(e => e.SomeProperty).IsModified = true
的操作(执行此操作,我认为您不需要附加实体)
请注意,此方法可能缺乏可伸缩性。您还可以对应在特定类中一起更新的参数进行分组。
这种方法是否适合您的需求?
答案 3 :(得分:0)
您可以使用反射并使用类似
的方法 UpdatePropertiesofPerson(Person personTobeUpdated, List<string> listOfPropertiesToBeUpdated)
{
foreach (var propertyName in listOfPropertiesToBeUpdated)
{
var propertyValue = personTobeUpdated.GetType().GetProperty(propertyName).GetValue(personTobeUpdated, null);
//sql update statement here using the propertyName and the value
}
}
答案 4 :(得分:0)
现在,一旦这段代码运行,我将遇到的问题是sql语句将运行并将NumberOfChildren更新为NULL。
您可以修改存储过程以处理该方案,方法是从现有行中进行选择,然后与从中间层发送的内容进行比较。这样你的存储过程也会运行得更好,因为参数嗅探会更少。
Create Procedure UpdatePerson
InputAge int, NumChildren int, Identifier int
Begin
Declare @NoOfChildrenCount Int
Declare @Age Int
Select @NoOfChildrenCount= NoOfChildren, @Age= Age from Person where Id = Identifier
If InputAge <> @Age
set @Age = InputAge
If NumChildren <> @NoOfChildrenCount
set @NoOfChildrenCount = NumberChildren
Update Person Set Age = @Age , NoOfChildren=@NoOfChildrenCount where Id = Identifier
End