问题
I'm working with .NET C# and Entity Framework.
I have a situation where I need to update an object in the database but I'll keep one property untouched. I'd like to know is it possible to do that?
Take the following class for example:
public class Person
{
public int PersonId { get; set; }
public string Name{ get; set; }
public int Age { get; set; }
public DateTime CreationDate { get; set; }
}
So I would provide a HTML form in a page for the client to edit a person. Example:
<form>
<input type="hidden" id="PersonId" value="1" />
<input type="text" id="Name" value="Cesar" />
<input type="text" id="Age " value="28" />
</form>
Then I'd grab the values and send to the repository to update that Person. But it does not make sense updating CreationDate, and I don't want to provide that possibility.
So I could do it in 2 different ways.
1) I could put it in the form as a hidden field and post it back. (but as I said I don't want to provide that possibility)
2) In the repository get the Person, update it's fields and leave CreationDate date the same and then save it:
void UpdatePerson(Person p){
var person = db.Persons.Find(PersonId);
person.Name = p.Name;
person.Age = p.Age;
db.Persons.Attach(person);
db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
}
I'd like to know a way that I could just pass "p" to the context and update it leaving CreationDate the way it is.
I hope I was clearer.
I'm sorry about the lack of information in the first post.
Thank you for your help.
回答1:
Personally, I use AutoMapper and use Ignore on the one field you don't want to copy. This way, if you ever add new columns to the table, you don't have to worry about adding them to your repository.
So, something like this...
void UpdatePerson(Person p) {
var person = db.Persons.Find(PersonId);
Mapper.CreateMap<Person, Person>()
.ForMember(dest => dest.CreationDate, opt => opt.Ignore());
Mapper.Map(p, person);
db.SaveChanges();
}
回答2:
Two other methods...
add a default to your SQL table
ALTER TABLE dbo.Person ADD CONSTRAINT
DF_Person_CreatedDate DEFAULT GetDate() FOR CreatedDate
use a backing field and default that to DateTime.Now
public DateTime CreatedDate
{
get { return createdDate; }
set { createdDate = value); }
}
private DateTime createdDate = DateTime.Now;
回答3:
This is what I use, using custom InjectNonNull (obj dest, obj src) it makes it fully flexible, even if you have two or more fields
[HttpPost]
public async Task<IActionResult> Post( [FromQuery]Models.Currency currency ) {
if ( ModelState.IsValid ) {
// find existing object by Key
Models.Currency currencyDest = context.Currencies.Find( currency.Id );
context.Currencies.Attach( currencyDest );
// update only not null fields
InjectNonNull( currencyDest, currency );
// save
await context.SaveChangesAsync( );
}
return Ok();
}
// Custom method
public static T InjectNonNull<T>( T dest, T src ) {
foreach ( var propertyPair in PropertyLister<T, T>.PropertyMap ) {
var fromValue = propertyPair.Item2.GetValue( src, null );
if ( fromValue != null && propertyPair.Item1.CanWrite ) {
propertyPair.Item1.SetValue( dest, fromValue, null );
}
}
return dest;
}
来源:https://stackoverflow.com/questions/20353665/ignore-one-property-on-update-entity-framework