AutoMapper: update child property instead of overwritting it - automapper-2

I have a class with a child property:
Person {
string Name;
Address Address {
string Street;
}
}
When I construct new Person object, I want automapper to execute something like:
var person = new Person();
person.Name = sourcePerson.Name;
person.Address = new Address();
person.Address.Street = sourcePerson.Address.Street;
but if I already have a Person object, I just want to fill it, and if my Person object already has Address set, to I want that Address object to be filled as well, not replaced. Essentially:
var person = GetExistingPerson();
...
Mapper.Map(sourcePerson, person); // this will fill person object
// here is what it does now (internally):
person.Name = sourcePerson.Name;
person.Address = new Address();
person.Address.Street = sourcePerson.Address.Street; // <-- not what I want
// here is what I do want to happen:
person.Name = sourcePerson.Name;
person.Address.Street = sourcePerson.Address.Street; // i.e. not override Address, but fill it.
Ideally I want to be able to configure AutoMapper to figure this out automatically, i.e. if Address is not null - then create and set it, if it is not null - then just update it.
Right now I use AfterMap as follows:
var map = Mapper.Create<SourcePerson, Person>();
map.ForSource(src=>src.Name,opt=>opt.MapFrom(dst=>dst.Name));
map.AfterMap((srcPerson, dstPerson) => {
if (dstPerson.Address == null) dstPerson.Address = Mapper.Map<Address>(srcPerson.Address); // set
else Mapper.Map(srcPerson.Address, dstPerson.Address); // fill
});
I do this because Address object is a self tracking entity and it has a state that I can not override.
Is there a way to refactor my code to not use AfterMap?

Related

Update context in SQL Server from ASP.NET Core 2.2

_context.Update(v) ;
_context.SaveChanges();
When I use this code then SQL Server adds a new record instead of updating the
current context
[HttpPost]
public IActionResult PageVote(List<string> Sar)
{
string name_voter = ViewBag.getValue = TempData["Namevalue"];
int count = 0;
foreach (var item in Sar)
{
count = count + 1;
}
if (count == 6)
{
Vote v = new Vote()
{
VoteSarparast1 = Sar[0],
VoteSarparast2 = Sar[1],
VoteSarparast3 = Sar[2],
VoteSarparast4 = Sar[3],
VoteSarparast5 = Sar[4],
VoteSarparast6 = Sar[5],
};
var voter = _context.Votes.FirstOrDefault(u => u.Voter == name_voter && u.IsVoted == true);
if (voter == null)
{
v.IsVoted = true;
v.Voter = name_voter;
_context.Add(v);
_context.SaveChanges();
ViewBag.Greeting = "رای شما با موفقیت ثبت شد";
return RedirectToAction(nameof(end));
}
v.IsVoted = true;
v.Voter = name_voter;
_context.Update(v);
_context.SaveChanges();
return RedirectToAction(nameof(end));
}
else
{
return View(_context.Applicants.ToList());
}
}
You need to tell the DbContext about your entity. If you do var vote = new Vote() vote has no Id. The DbContext see this and thinks you want to Add a new entity, so it simply does that. The DbContext tracks all the entities that you load from it, but since this is just a new instance, it has no idea about it.
To actually perform an update, you have two options:
1 - Load the Vote from the database in some way; If you get an Id, use that to find it.
// Loads the current vote by its id (or whatever other field..)
var existingVote = context.Votes.Single(p => p.Id == id_from_param);
// Perform the changes you want..
existingVote.SomeField = "NewValue";
// Then call save normally.
context.SaveChanges();
2 - Or if you don't want to load it from Db, you have to manually tell the DbContext what to do:
// create a new "vote"...
var vote = new Vote
{
// Since it's an update, you must have the Id somehow.. so you must set it manually
Id = id_from_param,
// do the changes you want. Be careful, because this can cause data loss!
SomeField = "NewValue"
};
// This is you telling the DbContext: Hey, I control this entity.
// I know it exists in the DB and it's modified
context.Entry(vote).State = EntityState.Modified;
// Then call save normally.
context.SaveChanges();
Either of those two approaches should fix your issue, but I suggest you read a little bit more about how Entity Framework works. This is crucial for the success (and performance) of your apps. Especially option 2 above can cause many many issues. There's a reason why the DbContext keep track of entities, so you don't have to. It's very complicated and things can go south fast.
Some links for you:
ChangeTracker in Entity Framework Core
Working with Disconnected Entity Graph in Entity Framework Core

nHibernate set referenced property by id

I have the following method which is called from Ajax:
[Authorize]
[ValidateInput(false)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public JsonNetResult CreateOrUpdateTimeRecord(TimeRecord tr)
{
TimeRecord trLocal;
if (tr.Id == -1 || tr.Id == 0)
{
trLocal = new TimeRecord
{
Description = tr.Description,
StartTime = tr.StartTime,
EndTime = tr.EndTime,
User =new myTimeMvc.Models.NHibernate.Models.User {Id = tr.User.Id},// _userRepo.Get(tr.User.Id),
Hdt = new Hdt {Id = tr.Hdt.Id}//_hdtRepo.Get(tr.Hdt.Id)
};
_timeRepo.Insert(trLocal);
}
else
{
trLocal = _timeRepo.Get(tr.Id);
trLocal.Description = tr.Description;
trLocal.StartTime = tr.StartTime;
trLocal.EndTime = tr.EndTime;
_timeRepo.Update(trLocal);
}
...
}
As you can see my TimeRecord has a reference to User and Hdt. Now I started to work with NHibernate Profiler which complains when I resolve my properties by loading them from their coresponding repositories. Which is clear to me since I actually don't need to query the database for that since I have the ID's for this objects.
User = _userRepo.Get(tr.User.Id),
Hdt = _hdtRepo.Get(tr.Hdt.Id)
But I'm not 100% sure if I can use this instead:
User =new myTimeMvc.Models.NHibernate.Models.User {Id = tr.User.Id},,
Hdt = new Hdt {Id = tr.Hdt.Id}
I guess NHibernate lazy proxies work the same way since they only contain just the ID of the related object and load the rest when it is needed. Do I have to attach this "new" oject anyway to my session?
Can someone tell me what is the correct way to do this?
Cheers,
Stefan
There are a few ways how to achieve that. One of them could be using the Load() method. Check Ayendes post: NHibernate – The difference between Get, Load and querying by id, an extract:
Load will never return null. It will always return an entity or throw an exception. Because that is the contract that we have we it, it is permissible for Load to not hit the database when you call it, it is free to return a proxy instead.
Other words, we can do something like this
User = _userRepo.Load(tr.User.Id),
Hdt = _hdtRepo.Load(tr.Hdt.Id)
Where the Load would be encapsulating the session.Load()

How can I rotate back?

I am developing a wcf service for Windows 8 APP. But I'm choked up at one point.
The following method, it is coming data in the database using entity. But this the data returns back to a class type. My question , if result is null what can I sent person who will this method
public AnketorDTO AnketorBul(string tc, string pass)
{
_entity = new AnketDBEntities();
var result = (from i in _entity.Anketors
where i.TC == tc
where i.Sifre == pass
select i).ToList();
if (!result.Any())
-->>> return new AnketorDTO();
Anketor anketor = result.First();
return Converter.ConvertAnketorToAnketorDTO(anketor);
}
with this methot I SENT it by creating a new class type but part which use this methot does not work because the values become null. how can we prevent it.
Client :
AnketorDTO anketor = await client.AnketorBulAsync(txtKullanici.Text, txtSifre.Password);
**if (anketor != null)
lblError.Text = anketor.Adi;**
else
lblError.Text = "Hata";
Can you try this method to see, if it works?
_entity = new AnketDBEntities();
var result = _entity.Anketors.FirstOrDefault(yourexpressions);

GTK# treeview hierarchical data display

I am currently working with mono and gtk#.
Regarding the TreeView there is this Tutorial.
I want to achieve the same thing thats presented under "Controlling how the model is used"
So i have the Song Class and the Render-Methods to display artist and title.
But I want to display it via a TreeStore instead of a ListStore. So that I have a Rootnode for each Letter and under this node all Artists starting with this letter should be displayed.
My problem how can I add these RootNodes to the TreeStore? And where should I add them?
songs.Add(new Song("Dancing Djs vs. Roxette", "Fading like a flower"));
songs.Add(new Song("Xaiver","give me the right"));
songs.Add(new Song("Daft Punkt","Technologic"));
TreeStore musicListStore = new TreeStore(typeof(Song));
foreach (var s in songs)
{
musicListStore.AppendValues(s);
}
treeview1.Model = musicListStore;
treeview1.AppendColumn("Artist", new CellRendererText(),new TreeCellDataFunc(RenderArtistName));
treeview1.AppendColumn("Title", new CellRendererText(),new TreeCellDataFunc(RenderSongTitle));
private void RenderArtistName(TreeViewColumn column, CellRenderer cell, TreeModel model, TreeIter iter)
{
Song s = model.GetValue(iter,0) as Song;
(cell as CellRendererText).Text = s.Artist;
}
private void RenderSongTitle(TreeViewColumn column, CellRenderer cell, TreeModel model, TreeIter iter)
{
Song s = model.GetValue(iter,0) as Song;
(cell as CellRendererText).Text = s.Title;
}
So i want to achieve that there are RootNodes for each letter and underneath each letter there should be all Artists listed starting with this letter.
My problem is how to add the letter to the TreeStore plus how do i know where to insert each Song then.
Here is a screenshot how i would like it to look like(I am not allowed to upload them directly. So i Had to use an external hosted. Sry):
Screenshot
You can build up your tree quite easily. Eg;
var store = new Gtk.TreeStore( typeof(string) );
// add a root node
var root = store.AppendValues("hello");
// add a child of the root
store.AppendValues(root,"world");
// add another child
var mono = store.AppendValues(root,"mono");
// add a second level child
store.AppendValues(mono,"gtk");
So, in the context of your music app..
// title, artist
var store = new Gtk.TreeStore( typeof(string), typeof(string) );
// make an index of top level nodes using thier TreeIters
var index = new Dictionary<string,Gtk.TreeIter>();
// add index nodes
foreach ( var letter in new List<string>{ "A", "B", "C" ... "Z" } ){
index[letter.ToLower()] = store.AppendValues( letter );
}
// add songs
foreach ( var song in songlist ){
var title = song.Title;
var artist = song.Artist;
var first = title.SubString(0,1).ToLower();
var iter = store[first];
// add this song
store.AppendValues( iter, title, artist );
}
You will have to do some extra work if you want to dynamically add index nodes, each time you add a node at a level all your treeiter values at that level or deeper become worthless.

Entity Framework: Update entity or add if it doesn't exist

I have a scenario where I have to update an entity if it exists or add a new one if it doesn't.
I would like to execute a single method for this (it would be great if it were a single trip to the server).
Is there something like that in EF?
Right now my code looks like this:
var entity = db.Entities.FirstOrDefault(e => e.Id == myId);
if (entity == null)
{
entity = db.Entities.CreateObject();
entity.Id = myId;
}
entity.Value = "my modified value";
db.SaveChanges();
But I would like to avoid the first query, something like this:
var entity = new Entity();
entity.Id = myId;
entity.Value = "my modified value";
db.AddOrAttach(entity);
db.SaveChanges();
Is there anything similar? or do I have to perform the first query no matter what?
Thanks
You have to perform the first query no matter what, unfortunately.
One option would be to write a stored procedure that performs a T-SQL MERGE then map it to a function import, though that would require that you pass the scalar values of the entity as parameters (and support for navigation properties would be done), but it would accomplish what you're after.
I ran some quick test code for editing in MVC 3 with EF 4 and it seems to work for edit with following code:
using (var context = new TestStackOverFlowEntities())
{
Person p = new Person();
p.Id = long.Parse(collection["Id"]);
p.FirstName = collection["FirstName"];
p.LastName = collection["LastName"];
context.People.Attach(p);
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Modified);
context.SaveChanges();
return RedirectToAction("Index");
}
Edit: I checked with creating new object too, you need to change this
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Added);
when Id == 0 //ie new object.
Quick and dirty code to add new is this:
using (var context = new TestStackOverFlowEntities())
{
Person p = new Person();
p.Id = 0;
p.FirstName = collection["FirstName"];
p.LastName = collection["LastName"];
context.People.Attach(p);
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Added);
context.SaveChanges();
return RedirectToAction("Index");
}
If you are just trying to limit code to clarify your controllers:
db.Attach(model);
db.SaveChanges(model);
Will update if the Entity Key exists, and create if it does not.