I've been trying to come up with a clean and reusable way to map entities to their DTOs. Here is an example of what I've come up with and where I'm stuck.
Entities
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
// Other properties not included in DTO
}
public class Address
{
public int ID { get; set; }
public string City { get; set; }
// Other properties not included in DTO
}
DTOs
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
}
public class AddressDTO
{
public int ID { get; set; }
public string City { get; set; }
}
Expressions
This is how I began to handle the mapping. I wanted a solution that wouldn't execute the query before mapping. I've been told that if you pass a Func<in, out> instead of Expression<Func<in, out>> that it will execute the query before mapping.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = new AddressDTO()
{
ID = person.Address.ID,
City = person.Address.City
}
}
}
One issue with this is that I already have an expression that maps an Address to an AddressDTO so I have duplicated code. This will also break if person.Address is null. This gets messy very quick especially if I want to display other entities related to person in this same DTO. It becomes a birds nest of nested mappings.
I've tried the following but Linq doesn't know how to handle it.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = Convert(person.Address)
}
public static AddressDTO Convert(Address source)
{
if (source == null) return null;
return new AddressDTO()
{
ID = source.ID,
City = source.City
}
}
}
Are there any elegant solutions that I'm missing?
If you want to create mappings manually then you can use Select on the collection in the following way:
Some test data:
var persons = new List<Person>
{
new Person() {ID = 1, Name = "name1", Address = new Address() {ID = 1, City = "city1"}},
new Person() {ID = 2, Name = "name2", Address = new Address() {ID = 2, City = "city2"}},
new Person() {ID = 3, Name = "name3", Address = new Address() {ID = 1, City = "city1"}}
};
Mapping methods:
public static PersonDTO ToPersonDTOMap(Person person)
{
return new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = ToAddressDTOMap(person.Address)
};
}
public static AddressDTO ToAddressDTOMap(Address address)
{
return new AddressDTO()
{
ID = address.ID,
City = address.City
};
}
Actual usage:
var personsDTO = persons.Select(x => ToPersonDTOMap(x)).ToList();
Keep in mind that if this was a real query is would not get executed as long as it was IQueryable, it would be executed once you materialize it (using ToList() for example).
However, I would consider using some framework which could do it (the mappings) for you automatically (if your mapping are as simple as provided example(.
Just use AutoMapper.
Example:
Mapper.CreateMap<Address, AddressDTO>();
Mapper.CreateMap<Person, PersonDTO>();
Your query will execute when the mapping is performed but if there are fields in the entity that you're not interested use Project().To<> which is available both for NHibernate and EntityFramework. It will effectively do a select on the fields specified in the mapping configurations.
Automapper is the best way .
For me, I use this for simple objects only, but I don't recommend it
public static class ObjectMapper
{
public static T Map<T>(object objfrom, T objto)
{
var ToProperties = objto.GetType().GetProperties();
var FromProperties = objfrom.GetType().GetProperties();
ToProperties.ToList().ForEach(o =>
{
var fromp = FromProperties.FirstOrDefault(x => x.Name == o.Name && x.PropertyType == o.PropertyType);
if (fromp != null)
{
o.SetValue(objto, fromp.GetValue(objfrom));
}
});
return objto;
}
}
And I call it like that wherever I want
var myDTO= ObjectMapper.Map(MyObject, new MyObjectDTO());
You could either use AutoMapper or write extension methods like these:
public static class PersonMapper
{
public static PersonDTO ConvertToDTO(this Person person)
{
return new PersonDTO { ID = person.ID, Name = person.Name, Address = person.Address.ConvertToDTO() };
}
public static IEnumerable<PersonDTO> ConvertToDTO(this IEnumerable<Person> people)
{
return people.Select(person => person.ConvertToDTO());
}
}
public static class AddressMapper
{
public static AddressDTO ConvertToDTO(this Address address)
{
return new AddressDTO { ID = address.ID, City = address.City };
}
public static IEnumerable<AddressDTO> ConvertToDTO(this IEnumerable<Address> addresses)
{
return addresses.Select(address => address.ConvertToDTO());
}
}
You could then map a Person object to a PersonDTO object like this:
public class Program
{
static void Main(string[] args)
{
Person person = new Person { ID = 1, Name = "John", Address = new Address { ID = 1, City = "New Jersey" } };
PersonDTO personDTO = person.ConvertToDTO();
Console.WriteLine(personDTO.Name);
}
}
I see the way you want to do it. I can propose you this solution:
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
public static Expression<Func<Entities.Person, PersonDTO>> PersonSelector
{
get
{
return person => new PersonDTO()
{
ID = x.Id,
Name = x.Name,
Address = x.Address
.Select(AddressDTO.AddressSelector)
};
}
}
}
public async Task<PersonDTO> GetPerson(int id)
{
var person = await _personRepository.Get(id, PersonDTO.PersonSelector);
return person;
}
public async Task<TResult> Get<TResult>(int id, Expression<Func<Person, TResult>> selector)
{
var result = await _context.Persons
.Where(x => x.Id == id)
.Select(selector)
.SingleOrDefaultAsync();
return result;
}
Related
I am developing micro-service with .NET Core.
The following code is working with an HttpPut request.
But if any field has empty or null value in our incoming JSON request, I want it to retrieve the previous value.
I don't want to constantly run the code below. Is there a short way around this?
if(updateCustomer.Surname != null && updateCustomer.Surname !=string.Empty)
{
customer.Surname = updateCustomer.Surname;
}
var serviceResponse = new ServiceResponse<GetCustomerDto>();
Customer customer = await _context.Customers.FirstOrDefaultAsync(c => c.Id == updateCustomer.Id);
var persons = (from p in _context.Customers where p.Id == updateCustomer.Id select p);
foreach (var person in persons)
{
person.Name = updateCustomer.Name;
person.Surname = updateCustomer.Surname;
person.BusinessCode = "123";
person.Phone = updateCustomer.Phone;
}
await _context.SaveChangesAsync();
serviceResponse.Data = _mapper.Map<GetCustomerDto>(customer);
Following the GetValueOrDefault() idiom from Nullable types, you can create a string extension method to select between two values like so:
public static class StringExtensions
{
public static string GetValueOrDefault(this string str, string alternative)
{
if(string.IsNullOrEmpty(str))
{
return alternative;
}
return str;
}
}
public class Program
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string BusinessCode { get; set; }
public string Phone { get; set; }
}
public static void Main()
{
Person previous = new Person
{
Name = null,
Surname = "Smith",
BusinessCode = "123",
Phone = "(555) 123-4567"
};
Person current = new Person
{
Name = "John",
Surname = string.Empty,
BusinessCode = "321",
Phone = "(555) 765-4321"
};
Person updated = new Person
{
Name = current.Name.GetValueOrDefault(previous.Name),
Surname = current.Surname.GetValueOrDefault(previous.Surname),
BusinessCode = current.BusinessCode.GetValueOrDefault(previous.BusinessCode),
Phone = current.Phone.GetValueOrDefault(previous.Phone)
};
}
}
I just started with Entity Framework and I was having difficulty generating a query for the following situation.
I currently have two model classes Student and Sport. A student can play multiple sports. This is what my models look like
public class DbContext : DbContext
{
public DbContext(): base("name=DbContext")
{
}
public DbSet<Student> MyStudents { get; set; }
public DbSet<Sport> MySports { get; set; }
}
public class Student
{
public List<Sport> Actions { get; set; }
public string Name { get; set; }
}
public class Sport
{
public string SportName { get; set; }
}
My question is how do I get a list of all sports played by all the students? In short I am looking for common sports. So basically in the following case
Student A played Sports : Soccer , Tennis , Bowling
Student B played Sports : Soccer , Tennis ,
Student C played Sport : Tennis
Then only Tennis should be returned
Using the DB schema you've provided you can get the common sports checking sports of each student:
var sports = new[]
{
new Sport { SportName = "Tennis" },
new Sport { SportName = "Soccer" },
new Sport { SportName = "Bowling" }
};
var students = new[]
{
new Student
{
Name = "Student 1",
Actions = sports
},
new Student
{
Name = "Student 2",
Actions = new[] { sports[0], sports[1] }
},
new Student
{
Name = "Student 3",
Actions = new[] { sports[0] }
}
};
// Or
var sports = context.Sports;
var students = context.Students;
// In case students' sports are objects (as in this sample) you can use such a query:
var commonSports = sports.Where(sport =>
students.All(student => student.Actions.Contains(sport)));
// In case you're going to check the sports by name, this:
var commonSports = sports.Where(sport =>
students.All(student => student.Actions.Any(studSport =>
studSport.SportName == sport.SportName)));
Console.WriteLine($"Comon sports: {string.Join(",", commonSports.Select(i => i.SportName))}");
// To get only names of common sports:
var sportNames = commonSports.Select(i => i.SportName);
Console.Read();
If you use a relational database it would be easier and (as for me) more logical to implement many-to-many relationship as described here:
var context = new DbContext()
var unique = context.MyStudents.SelectMany(student => student.Actions.Select(sport => sport.SportName)).Distinct();
you just do this :
var commonSports = Context.Students.SelectMany(x=>x.Actions).GroupBy(x => x.SportName).Where(x=>x.Count()==items.Count(c=>c.Actions!=null)).Select(x=>x.Key).ToList();
I hope it been helpful .
To achieve this you might want to first set up some kind of model class, this isn't strictly necessary but might make things clearer for you:
public class StudentWithSports()
{
public string Name {get;set;}
public List<string> Sports {get;set;}
}
You can then populate your model from your context:
using(var context = new DbContext())
{
List<StudentWithSports> list = context
.Students
.Include(stu => stu.Actions)
.Select(stu => new StudenWithSports
{
Name = stu.Name,
Sports = stu.Actions.Select(act => act.SportName).ToList()
}).ToList();
}
If you don't want to create a model you could just do:
var list = context
.Students
.Include(stu => stu.Actions)
.Select(stu => new {
Name = stu.Name,
Sports = stu.Actions.Select(act => act.SportName).ToList()
}).ToList();
Which will give you a list of anonymous objects with the same properties.
The essence of my answer is the linq query, but I created a couple of classes to model your EF classes to show it works.
Student student1 = new Student
{
Name = "John",
Actions = new List<Sport>
{
new Sport { SportName = "Tennis" },
new Sport { SportName = "Soccer" },
new Sport { SportName = "Bowling" }
}
};
Student student2 = new Student
{
Name = "Mary",
Actions = new List<Sport>
{
new Sport { SportName = "Tennis" },
new Sport { SportName = "Soccer" }
}
};
Student student3 = new Student
{
Name = "Jane",
Actions = new List<Sport>
{
new Sport { SportName = "Tennis" }
}
};
IEnumerable<Student> students = new List<Student>
{
student1,
student2,
student3
};
var query = from s in students
select new
{
s.Name,
Sports = from sp in s.Actions
select sp.SportName
};
var result = query.ToList();
for (int i = 0; i < result.Count(); i++)
{
Console.Write(result[i].Name + " played sports: ");
foreach (var sport in result[i].Sports)
Console.Write(" " + sport);
Console.WriteLine();
}
Well your Db design isn't right because you have many to many relation between MyStudents and MySports tables. You have to add joint table between Students and Sports. You can call it StudentsSports
public class DbContext : DbContext
{
public DbContext(): base("name=DbContext")
{
}
public DbSet<Student> MyStudents { get; set; }
public DbSet<StudentsSport> StudentsSports { get; set; }
public DbSet<Sport> MySports { get; set; }
}
public class Student
{
public int ID { get; set; }
public List<StudentsSport> Actions { get; set; }
public string Name { get; set; }
}
public class Sport
{
public int ID { get; set; }
public string SportName { get; set; }
}
public class StudentsSport
{
public int ID { get; set; }
[ForeignKey(Student)]
public int StudentID { get; set; }
[ForeignKey(Sport)]
public int SportID { get; set; }
}
Then you can just do
var listOfActions = MyStudents.Select(s => s.Actions.Select(a => a.SportID));
var intersection = listOfActions
.Skip(1)
.Aggregate(
new HashSet<T>(listOfActions.First()),
(h, e) => { h.IntersectWith(e); return h; }
);
EDIT:
If you have students without sports then you will always get empty intersection list. If you don't want that then you will have to filter them
var listOfActions = MyStudents.Select(s => s.Actions.Select(a => a.SportID)).Where(c => c.Any());
I got this code and it works without problems. But i sense there is much better way to do this.
namespace Repositories
{
public class AuthorRepository : IAuthorRepository
{
public List<Author> GetAllFromRepo()
{
using (AppContext myDB = new AppContext())
{
List<Author> authorsFromRepo = new List<Author>();
foreach (var item in myDB.Authors)
{
authorsFromRepo.Add(new Author()
{
Books = new List<Book>(),
ID = item.ID,
FirstName = item.FirstName,
LastName = item.LastName
});
}
return authorsFromRepo.ToList();
}
}
}
}
When i try something along the lines of this:
public List<Author> GetAllFromRepo()
{
using (AppContext myDB = new AppContext())
{
List<Author> authorsFromRepo = new List<Author>();
authorsFromRepo = myDB.Authors.ToList();
return authorsFromRepo;
}
}
I always get this error:
Value cannot be null.
Parameter name: source
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
Source Error: Line 33: return authors.Select(x => new AuthorViewModel()
Any Help?
The model where the error takes me
namespace Services
{
public class AuthorService : IAuthorService
{
private readonly IAuthorRepository _AuthorRepository;
public AuthorService(IAuthorRepository authorRepository)
{
_AuthorRepository = authorRepository;
}
public List<AuthorViewModel> GetAll()
{
List<Author> authors = _AuthorRepository.GetAllFromRepo();
return authors.Select(x => new AuthorViewModel()
{
ID = x.ID,
FullName = $"{x.FirstName } {x.LastName} ",
Books = x.Books.Select(g => new BookViewModel()
{
ID = g.ID,
Name = g.Name
}).ToList()
}).ToList();
}
}
}
To add again, everything works fine if i use the first example of code.
When i try something shorter like
return myDB.Authors.ToList();
i get the error.
when i change to:
return authors.Select(x => new AuthorViewModel()
{
ID = x.ID,
FullName = $"{x.FirstName } {x.LastName} ",
Books = {}
}).ToList();
It works then... but this means it doesn't read the author books...
I had to change the model for Authors to
namespace Entities
{
public class Author
{
// this is what a had to add here
// From here
public Author()
{
Books = new List<Book>();
}
// to here
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Book> Books { get; set; }
}
}
So It wont give me any errors when x.Books is null.
I'm approaching to document database and I'm little bit confused how to map documents relationship, in a situation as follow
public class Person
{
public Person()
{
}
public int Id { get; set; }
public string Name { get;set;}
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public Car() { }
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set;}
}
A person has one or more cars for example in this way I can query the db as follow
public Car Get(int id)
{
Car car = null;
using (IDocumentSession session = store.OpenSession())
{
car = session.Include<Car, Person>(x => x.PersonId).Load<Car>(id);
bool isLoaded = session.Advanced.IsLoaded("people/" + car.PersonId); // true!
}
return car;
}
and it's everything ok, the client makes just one request, but if I have a person and I want to show all his cars how can I query the db to do just a request?
I think tha I must modify the model putting a List<int> Cars in Person for reference his cars.
Note that I don't want to embed Cars in the Person document because Cars can be referenced from others document.
Thanks.
You can do it like this:
using (IDocumentSession session = store.OpenSession())
{
var carsForOne = session.Query<Car>()
.Include(x=>x.PersonId)
.Where(x=>x.PersonId == "people/1")
.ToList();
var person = session.Load<Person>("people/1");
}
This make just a single db request.
You can index the Cars collection and load all the cars from the index.
The index would look like this:
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
The CarView class is identical to the Car class, but can be changed to better fit the indexing needs.
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
You'll need to execute the index before being able to use it:
new CarIndex().Execute(store);
Loading the cars for a certain person would look like this:
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForIndexing(store); // from RavenTestBase
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
If you want to load the person and their cars in a single database request, use lazy loading:
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Complete test (needs xunit and RavenDB.Tests.Helpers nugets):
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using System;
using System.Linq;
using Xunit;
namespace SO41547501Answer
{
public class SO41547501 : RavenTestBase
{
[Fact]
public void SO41547501Test()
{
using (var server = GetNewServer())
using (var store = NewRemoteDocumentStore(ravenDbServer: server))
{
new CarIndex().Execute(store);
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForAllRequestsToComplete(server);
WaitForIndexing(store);
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
using (IDocumentSession session = store.OpenSession())
{
server.Server.ResetNumberOfRequests();
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Assert.Equal("A", personValue.Name); // person data loaded
Assert.Equal("A", resultsValue.First().Name); // cars data loaded
Assert.Equal(1, server.Server.NumberOfRequests); // only one request sent to the server
}
}
}
}
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
}
I want update family of a person who his name is pejman.
This is my object Class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set;}
public DateTime BirthDate { get; set; }
public bool IsMale { get; set; }
public byte[] Image { get; set; }
public byte[] RowVersion { get; set; }
public virtual Person Parent { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumber { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual PersonInfo PersonInfo { get; set; }
}
and my method for updating is: (in Program.cs)
public static void Update(string name, string family)
{
var _person = new Person() { FirstName = name, LastName = family };
using (var newContext = new MyDbContext())
{
newContext.Persons.Attach(_person);
newContext.Entry(_person).Property(X => X.LastName).IsModified = true;
newContext.SaveChanges();
}
}
but it doesn't work! what is the problem?
EDIT: assume that i don't know person's Id, and i just know person's name, is there any way to update person's family?
You are missing an Id field when creating an instance of Person object. Because of this Entity Framework is not able to find an existing Person.
Your code should look like this:
public static void Update(int id, string name, string family)
{
var _person = new Person() { Id = id , FirstName = name, LastName = family };
using (var newContext = new MyDbContext())
{
newContext.Persons.Attach(_person);
newContext.Entry(_person).Property(X => X.LastName).IsModified = true;
newContext.SaveChanges();
}
EDIT: assume that i don't know person's Id, and i just know person's name, is there any way to update person's family?
I'm assuming that the FirstName field of Person class contains the person's name, and updating the person's family means updating the LastName field.
The first step is to get all Person records with FirstName equals the person's name, let's say it's "pejman" so the code would be as below.
var personsToUpdate = newContext.Persons.Where(o => o.FirstName == "pejman");
The next step is enumerate personsToUpdate and set the LastName property to the family name you want, then call .SaveChanges() method of the DbContext to submit the changes to the database. Let's say you want to update the person's family name to "MyFamilyName", the code would be as below
foreach (Person p in personsToUpdate)
{
p.LastName = "MyFamilyName";
}
newContext.SaveChanges();
The following is the modified code of your Update method with the name and family parameter.
public static void Update(string name, string family)
{
using (var newContext = new MyDbContext())
{
// get all Persons with FirstName equals name
var personsToUpdate = newContext.Persons.Where(o => o.FirstName == name);
// update LastName for all Persons in personsToUpdate
foreach (Person p in personsToUpdate)
{
p.LastName = family;
}
newContext.SaveChanges();
}
}
For resolving this error i got values by ID from database stored in Var Temprc.
Then updated the field Password which i wont to update.
Then attached temprc to my Userregistrations model.
Then Marked PasswordConfirm isModified.
then Savechanges();
using (var db = new Entities())
{
var temprc = _reg.GetUserByID(Convert.ToInt32(Session["LogedUserID"]));
temprc.PasswordConfirm = U.NewPassword;
db.Userregistrations.Attach(temprc);
db.Entry(temprc).Property(x => x.PasswordConfirm).IsModified = true;
db.SaveChanges();
}
assuming you have the instance of Person that the db can find (as mentioned by Paweł Bejger):
public class Person
{
/// <summary>
/// USAGE: await UpdateDbEntryAsync(myPerson, d => d.FirstName, d => d.LastName);
/// </summary>
async Task<bool> UpdateDbEntryAsync<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class
{
try
{
var db = new RtTradeData.Models.ApplicationDbContext();
var entry = db.Entry(entity);
db.Set<T>().Attach(entity);
foreach (var property in properties)
entry.Property(property).IsModified = true;
await db.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("UpdateDbEntryAsync exception: " + ex.Message);
return false;
}
}
/// <summary>
/// The idea is that SomeFunction already has the instance of myPerson, that it wants to update.
/// </summary>
public void SomeFunction()
{
myPerson.FirstName = "Another Name"; myPerson.LastName = "NewLastName";
UpdateDbEntryAsync(myPerson, d => d.FirstName, d => d.LastName);
}
/// <summary>
/// Or directly requesting the person instance to update its own First and Last name...
/// </summary>
public void Update(string firstName, string lastName)
{
FirstName = "Another Name"; LastName = "NewLastName";
UpdateDbEntryAsync(this, d => d.FirstName, d => d.LastName);
}
Person myPerson = new Person { PersonId = 5, FirstName = "Name", LastName = "Family" };
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
see as well update a single field in Entity Framework
and Entity Framework update single
The following worked for me:
public ActionResult ChangePassword(Account account)
{
try
{
if (ModelState.IsValid)
{
db.Accounts.Attach(account);
db.Entry(account).Property(x => x.Password).IsModified=true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
raise = new InvalidOperationException(message, raise);
}
}
ModelState.AddModelError("", raise);
}
return View(account);
}