This is a migrated thread and some comments may be shown as answers.

Automapper - Update object ORM

18 Answers 1758 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Sam
Top achievements
Rank 1
Sam asked on 05 Feb 2013, 12:03 PM

 am trying to update an object using telerik openaccess orm and automapper, it works for adding the object to scope but not update.

I saw someone having same issue, but the answer didn't really help me. here is my code which doesn't update my object :

try
            {
                if (!scope.Transaction.IsActive)
                    scope.Transaction.Begin();

                ObjQ objq = get_Q(scope, Id);
                bool isNew = false;

                if (objq == null)
                {
                    objq = new ObjQ();
                    isNew = true;
                }

                AutoMapper.Mapper.CreateMap<ObjQ , ObjQ >();

                
               objq = AutoMapper.Mapper.Map<ObjQ , ObjQ>(srcQ);
if (isNew) { scope.Add(objq); } scope.Transaction.Commit(); success = true; }

after this line I can see my properties reflecting the new changes but it is not the same in database 
 objq = AutoMapper.Mapper.Map<ObjQ , ObjQ>(srcQ);

18 Answers, 1 is accepted

Sort by
0
Doroteya
Telerik team
answered on 08 Feb 2013, 08:12 AM
Hello Sam,

The update does not work as expected because the following line of code:
objq = AutoMapper.Mapper.Map<ObjQ , ObjQ>(srcQ);
creates a new object. In other words, even if the previous instance of the object was tracked for changes from the context, currently the latter is not aware of the existence of the new object.

A solution to the issue could be to call the AttachCopy() method of the context for the new object. With that you will allow the context to take care for the updates of the object. I suggest you checking the information about attaching and detaching objects available in this documentation article.

Another solution that uses the AutoMapper would be to try the following overload of the same method you used:
AutoMapper.Mapper.Map(srcQ, objq);

It transfers the data between the objects without creating new objects and therefore does not break the connection between the context and the updated object.

I hope that works for you. If you have any other questions or experience issues with the suggested solution, do not hesitate to get back to us.

Greetings,
Doroteya
the Telerik team
Q3'12 SP1 of OpenAccess ORM packs Multi-Table Entities mapping support. Check it out.
0
Nuno
Top achievements
Rank 2
answered on 08 Mar 2014, 01:09 PM
Well, I have to say that in my case, I came to find that Telerik Data Access doesn't like AutoMapper (or ValuInjecter for that matter). This code does not work:

if (manutencao == null)
            {
                throw new ArgumentNullException("Manutencao", "O argumento não pode ser nulo.");
            }
 
            OBJ.Manutencao dbManutencao = this.mManutencaoRepository.Get(manutencao.ManutencaoID);
 
            try
            {
                if (dbManutencao == null)
                {
                    this.mManutencaoRepository.Add(manutencao);
                }
                
                Mapper.Reset();
                Mapper.CreateMap<Manutencao, Manutencao>();
                Mapper.Map<Manutencao, Manutencao>(manutencao, dbManutencao);
 
                this.mUnitOfWork.SaveChanges();
 
                return true;
            }
            catch (Telerik.OpenAccess.OpenAccessException)
            {
                throw;
            }

Some properties do not get correctly mapped. 
0
Doroteya
Telerik team
answered on 12 Mar 2014, 08:58 AM
Hi Nuno,

I am sorry to hear that you are experiencing issues.

However, I was unable to completely understand the scenario on your side. Could you provide us with the following information:
1. What is the scenario you need to implement?
2. What is the behaviour you experience on your side?
3. What are the steps that lead to the behaviour?
4. What is the expected result?
5. If there are any errors, what are their messages?
6. What is the version of Telerik Data Access on your side?
7. Do you use a domain model (an .rlinq file) or a fluent model?

Any additional details you find relevant would be appreciated.

I am looking forward to your feedback.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 12 Mar 2014, 09:52 AM
Hi Doroteya!

Replying to your questions:
1. I have an MVC 4 application in which there are no view models, since I use Telerik's Data Access Entities directly as my Model. I did implement the repositories and the service classes on my own (inspired by the Data Access demos, off course); In the service classes I'm using automapper to update my entities by getting the data access tracked entity and then mapping the submitted model instance to the tracked instance;
2. What I see is that the properties do not get mapped and some how Data Access then is unable to persist the tracked entity. One thing I'm seeing is that there are properties with values in the tracked instance that after the map lose those values, even though the source instance do have values for that properties; After that, there is an SQL error saying that those properties are null;
3. The steps are those on the code in my previous post. Nothing more.
4. The expected result should be a "perfect" map and no issues saving the changes;
5. The SQL Server replies with the column can not be null;
6. I'm using the latest version;
7. I'm using a domain model;

If you should feel that a support ticket is needed, I'll be happy to do that.

Regards!


0
Doroteya
Telerik team
answered on 18 Mar 2014, 11:54 AM
Hello Nuno,

Thank you for your patience and cooperation.

Based on the provided information I used the ASP.NET MVC 4 using a Domain Model example from Telerik Data Access Samples Kit to test the scenario you need to implement. I focused on two main cases:
- When dbManutencao exists in the database.
- When dbManutencao does not exist in the database.

In the first case, the attempt to replace the values in the dbManutencao object with those from the manutencao object produces an error, which states that Telerik Data Access does not change the value of the primary key (Telerik.OpenAccess.Exceptions.UnsupportedException: Unsupported Operation: Change of identity is not supported.). This error is the expected one in such scenarios. The overload of the Map() method here is:
Mapper.Map<Manutencao, Manutencao>(manutencao, dbManutencao);
In the same case, if I use execute the next statement, the values are copied to the dbManutencao object, it is no longer tracked by the context, and no changes are persisted to the database:
dbManutencao = Mapper.Map<Manutencao, Manutencao>(manutencao);
Here, I observe the behavior you describe in point 2, and if I attach the object to the context, I get the error you experience. 

In the second case, when dbManutencao is null (there is no object with this ID in the database), the attempt to copy the values from manutencao was successful. On the call to the SaveChanges() method the manutencao object was persisted to the database and dbManutencao was its exact copy, which was not tracked by the context. In this case, the overload of the Map() method I used was:
dbManutencao = Mapper.Map<Manutencao, Manutencao>(manutencao);
In the same case, if I use the overload of the Map() method shown below, the values from manutencao are not transferred to dbManutencao and the latter remains null.
Mapper.Map<Manutencao, Manutencao>(manutencao, dbManutencao);

Based on this outcome from the tests, I would suggest to you to separate the logic that adds new objects to the database from the logic that updates an existing object.

I hope you find this feasible. I am looking forward to solving the issue with you.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 27 Mar 2014, 04:59 PM
HI Doroteya,

I've been with little time to press on this. I'll have to check your suggestion and see if it helps.

Thanks!
0
Nuno
Top achievements
Rank 2
answered on 22 Dec 2014, 12:24 PM
Hi!

I've returned to this issue recently, since I have been engaged in some other projects. I decided to come here and say that, as far as I'm concerned, using a mapper to update entities is a no go, no matter the approach used (I've tried AutoMapper and all the suggested overloads and also ValueInjecter).

I guess I'll have to go "old school" and write all the mappings manually... Do you guys have knowledge of any mapper working on this scenarios?

Thanks!
0
Nuno
Top achievements
Rank 2
answered on 22 Dec 2014, 01:23 PM
Well... i might have jump the gun here. In fact, I found a way to make AutoMapper work for updates. I think. See this code:

Mapper.Reset();
Mapper.CreateMap<OBJ.SlideShow, OBJ.SlideShow>().ForMember(p => p.SlideShowID, o => o.Ignore())
                                                            .ForMember(p => p.ZonasConteudo, o => o.Ignore());
Mapper.Map(slideShow, dbSlideShow);

This actually worked for an update operation (it uses AutoMapper). The difference here is that I explicitly ignore the Key property and also the navigation property "ZonasConteudo". After doing so, no errors and values correctly mapped... My take on this is as long as the properties are value types, they will get mapped.

The fact that, in this case, there was a property called "ZonaConteudoID" which is FK (ZonaConteudos is a nav prop from this) it was getting zeroed by the mapper when it tried to map the nav property. Ignoring it seemed to solve the issue here.

Which poses a chalenge when there are collection properties that need to be mapped... Will get to that in an instance, I'll bet... :)
0
Doroteya
Telerik team
answered on 25 Dec 2014, 01:09 PM
Hello Nuno,

Thank you for the input. I am glad that things are currently working on your side.

On our side, we did a little bit of testing our integration with AutoMapper and we had summarized our experience in this blog post.

I hope you find it feasible.



Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 09 Jan 2015, 06:12 PM
Hi Doroteya,

I've ended up, as I explained, solving my issues. Beside that, I've abandoned AutoMapper and I'm currently using ValueInjecter. It has a simpler approach and it is more flexible (IMHO).
0
Doroteya
Telerik team
answered on 14 Jan 2015, 12:51 PM
Hello Nuno,

Thank you for getting back to us.

While we haven't tested an integration between Data Access and ValueInjecter, if you experience Data Access related issues, do let us know.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 14 Jan 2015, 02:14 PM
Hi!

Will do, Doroteya, don't worry. Also, I'm thinking on putting together a sample and publish it using Data Access and ValueInjecter, providing all scenarios I need work. ;)
0
Doroteya
Telerik team
answered on 16 Jan 2015, 05:16 PM
Hi Nuno,

Such a sample from your side will appreciated.

I am looking forward to having a look at it.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 29 Jan 2015, 04:16 PM
Hello,

On the subject of using ValueInjecter, the code I gave as example here, can be replaced by the following:
dbSlideShow.InjectFrom<IgnoreNulls>(slideShow, new IgnorePropertiesInjection("SlideShowID, ZonasConteudo"));

Much simpler, same result. :) The IgnoreNulls part is a custom injection I'm using. More on ValueInjecter can be found in codeplex and I'll try uploading a working example, as soon as I can on how to use this with OpenAccess.

Cheers!
0
Nuno
Top achievements
Rank 2
answered on 29 Jan 2015, 04:20 PM
Just noticed I forgot to post the IgnorePropertiesInjection code. Sorry about that. Here you have both IgnoreNulls and IgnoreProperties:

public class IgnoreNulls : ConventionInjection
{
    protected override bool Match(ConventionInfo c)
    {
        return c.SourceProp.Name == c.TargetProp.Name
              && c.SourceProp.Value != null;
    }
}
 
public class IgnorePropertiesInjection : LoopValueInjection
{
    private readonly IEnumerable<string> mIgnores;
 
    public IgnorePropertiesInjection(params string[] s)
    {
        mIgnores = s;
    }
 
    protected override bool UseSourceProp(string sourcePropName)
    {
        return !mIgnores.Contains(sourcePropName);
    }
}

0
Doroteya
Telerik team
answered on 03 Feb 2015, 11:03 AM
Hi Nuno,

Thank you for the additional input.

Regarding the ValueInjecter sample, I would recommend you to post it in the Data Access code libraries section. There you will be able to attach files to the threads and the Data Access community can benefit from them.

I am looking forward to taking a look at the sample.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
Nuno
Top achievements
Rank 2
answered on 03 Feb 2015, 11:21 AM
Hello Doroteya,

I'll upload the sample there, as soon as I can, off course. :)

Cheers!
0
Doroteya
Telerik team
answered on 06 Feb 2015, 07:43 AM
Hello Nuno,

Thank you in advance for the understanding and the contribution.


Regards,
Doroteya
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
Tags
General Discussions
Asked by
Sam
Top achievements
Rank 1
Answers by
Doroteya
Telerik team
Nuno
Top achievements
Rank 2
Share this question
or