How do I copy an object with NHibernate - c#

I am using Nhibernate (I am a complete noob), and what I want to be able to do is copy an entity that is loaded from the database and save it with a new Id... has anyone run into this situation? Any help would be very appreciated.

Just do new MyClass() and copy everything except the Id. You can use reflection for that.

I need to do exactly this for a very complex set of objects and what I have found so far is:
NHibernate does not exactly support this.
If you try to simply replace the Id of an object you got from a session, you will get an Nhibernate error: identifier of an instance of was altered from <9ae3868d-17bf-4314-ba0c-4eb3b44b1a2e> to <2b2b67c6-a421-48c4-836c-4c27f6481718>
If the session no longer knows about the objects it retrieved, i.e if you evict them before saving and flushing, just changing the ids will now work. So you could write code like this:
public void CloneStudent(Guid studentId)
{
// Get existing student
Student student = _session.Get<Student>(studentId);
// Copy by reference
Student newStudent = student;
// Reset Id to do quick and dirty clone
newStudent.Id = Guid.NewGuid();
newStudent.Sticker = "D";
// Must evict existing object or Nhibernate will throw object modified error
_session.Evict(student);
// Save new object
_session.Save(newStudent);
_session.Flush();
}
The problem with this is if your object graph has any depth you have to be sure to evict the entire set, and then you may need the originals in the session still you have to retrieve them again. This is a logistical headache and yields code with very obscure and convoluted intentions.
I do not recommend.
What is more commonly done is serialize to a binary stream and reconstitute this stream into a new set of objects. Fine, but only works if your objects are all serializable.
That is not the case for me, what I am doing is I wrote manual code to make deep copies of an object graph using copy constructors. This is complex and also can lead to maintenance issues, but if the objects cannot be serialized there are few better alternatives.
Sorry, deep copying objects remains a complicated task if serialization is not an option.

Related

Automapper transform source just temporarily

I write a generic possibility to convert from database object to business object.
My business object contains custom attributes and depending on them, I like to make specific operations on them.
On reading from db its quite easy because I can use aftermap (not perfect solution, cause I have to do it by reflection and set the value depending on it)
But on writing back to the database I have to do it beforeMap but this would change the source permanent, but I just like it in a transient way. So do the operation with Source on the fly but do not change source object.
It's a generic option so I can't work with properties.
protected static T MapFromDatabaseWithConversion<T, TSource>(TSource source) where T : MappingModel, new()
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, T>().AfterMap((src, dest) => dest.ConvertFromDatabase()));
return config.CreateMapper().Map<T>(source);
}
Do you have any solution for the check on the fly the attribute of a property and change the value depending on it - or you have any idea to change source only on the fly, so not write the result of source operation to src obj?
Thank you very much.
I think you have to include value tracking in your objects. For each class member you would need a boolean to reflect if the value changed, and a method that checks them all at once such as isObjectChanged(). You can hard code this or wrap your object in a Proxy object at runtime, which is more complicated, but does not clutter you class with value tracking data/methods. On the other hand, Java Data Objects (https://db.apache.org/jdo/) can do this for you by re-compiling your class files to include value tracking within the class about changing values. It takes a bit to set up and may be overkill for your specific question, but I have used it many times when targeting multiple data sources in the same project such as a database or spreadsheet. JDO allows me to use the same code with a different data type manager that can be swapped at runtime. You can also target a No-SQL database and other data stores as well.

How to load an Entity Framework data object without explicitly setting each property

I want to be able to do something like the following:
var book = new Book();
book.LoadByPrimaryKey(id); //returns bool
The issue I am coming across is I can't figure out if there is a simple way to load data into an object generated using Entity Framework. I understand how to grab the information needed to fill the object, but is there a simple way to fill out all the properties of an object without explicitly going through each property and setting it to the desired value? In C# I cannot simply type:
this = db.Books.Single(d => d.BookId == id);
I instead have to explicitly set each property:
var book = db.Books.Single(d => d.BookId == id);
this.Title = book.Title;
this.PageCount = book.PageCount;
...
Is there a way around doing this when wanting to load up an object? Maybe something with a DbDataReader? I have used the data reader to load DataTables, but can't figure out how to use them to populate an object. Maybe I'm over thinking it.
When you need to copy all of the properties from one object to another you can
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
As David Browne previously answered:
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
The answer he gave you is correct. But I'm want to extend it and explain why.
First, let put some concept here. When we go further in programming techniques, sometimes, the working answer, it not enough. Although what you trying to do is a valid solution for the problem, there is some issue with it.
The is a concept that is called S.O.L.I.D. The first letter (S) stands for Single Responsibility Principle. This means that one object should have only one responsibility.
The problem in your approach is you are putting multiple responsibilities in a single object:
Hold/Transport information about a book.
Load from a remote server (in this case a DataBase) information about a book.
You probably googled this issue before post here, and I suspect you found nothing useful. Now the reason you found nothing is because this is a bad approach, it goes against the SOLID concepts, and it breaks several interation with possible Design Patterns. So this is why you probably found nothing, there is no previous conceived tool of workaround to this problem, because this is a discouraged approach, so no one, with a little understand of program techniques, will help you.
Therefore, we go back to the answer that David Browne gave you. To use Automapper (the simplest of the suggestions). You need to change your approach. Consider to separate each responsibility in a different class:
class BookDA // DAO = data access
{
private MyDbConnection db;
public BookTO Get()
{
var book = db.Books.Single(d => d.BookId == id);
return book;
}
}
class BookTO // TO = transport object
{
public string Name { get; set; }
}
In the code above each responsibility is associated with a different class. This answer became too long but I hope it helps.

A change in one object changes the second one too

I'm creating two objects and assign them with a data from IsolatedStorage.
But when I change one object the second one changes too. ( I think the problem may be the pointers are the same, but I can't solve it. )
private ArrayOfClsSimpleData lstUsers;
private ArrayOfClsSimpleData tmpLstUsers;
in class' globals
tmpLstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
The first status of the arrays:
Debug.Write(lstUsers.Count)
Output: 2
Debug.Write(tmpLstUsers.Count)
Output: 2
The counts are the same as expected. But, after I add an item to one list, the other list gets updated too and the counts are still same.
lstUsers.Add(new ArrayOfClsSimpleData());
Debug.Write(lstUsers.Count)
Output: 3
Debug.Write(tmpLstUsers.Count)
Output: 3
EDIT : IsolatedStorageHelper class is something to help to get objects, save object etc. that I do use for simplifying things, so just think it as getting objects from IsolatedStorage.
it is implemented like this:
public static T GetObject<T>(string key)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key]; // return the object
}
return default(T); // if key doesn't exists , return default object
}
So it just gets it from IsolatedStorage.
If you don't know isolated storage you can see it from here
So, how can I fix the code so that I can change one without changing the other?
So, basically lstUsers and tmpLstUsers are references to the same object. All you have to do is to create a new one and copy content from the original. If you need a quick solution, then you can do it like this (code below). I just guess that ArrayOfClsSimpleData is some kind of array.
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey");
tmpLstUsers = new ArrayOfClsSimpleData();
foreach (object user in lstUsers) // I don't know the type of objects in ArrayOfClsSimpleData, so I wrote 'object', but you should use the actual type
tmpLstUsers.Add(user);
The problem is that IsolatedStorage is just returning two pointers to the same data. So unless you copy the data, all changes will ultimately be to the same underlying data.
Think of it as two copies of your home address. Anything you change on your home affects all copies of your address since it is just an address and not the home itself.
What you will want to do is clone your object. Built in collections have clone or copy methods built in to do shallow copies, or if you built something yourself you will need to implement it yourself
The easiest way is to implement the IClonable interface and to use the clone method to achieve your copying.
https://msdn.microsoft.com/en-us/library/System.ICloneable.aspx
This basically involves going through and calling member wise clone for each complex object (which will copy all value types for you)
https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
I don't think cloning is necessary. Just create a new list instead of operating on the same instance. You can do that by calling ToList() on the returned instance:
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey").ToList();
Can't you use the Clone() method of IClonable while fetching the object? looks like both list objects are getting same reference objects.

C# NHibernate with Spring LazyInitializationException when using the data

I'm working on an NHibernate project, and where I had trouble loading collections earlier (http://stackoverflow.com/questions/4213506/c-hibernate-criteria-loading-collection), I now have problems using data.
I'm using C# in combination with the NHibernate and Spring.Net framework, and I get an LazyInitializationException after I load for instance an 'ordercredit', and then accessing an object of the ordercredit.
I use this code for getting the OrderCredit:
OrderCredit oc = CreditService.getOrderCredit(ordercredit.Id);
The code I use for loading is done using a DAO implementation:
[Transaction(TransactionPropagation.Required, ReadOnly = true)]
public OrderCredit GetOrderCredit(long ordercreditid)
{
var creditrules = Session.CreateCriteria(typeof(OrderCredit));
creditrules.Add(Restrictions.Eq("Id", ordercreditid));
return creditrules.List<OrderCredit>()[0];
}
When I run this on my local machine, everything works fine, and I actually intended to load a list of those 'ordercredits', but that went wrong as well, so I tried a simpler step first.
The objects within the 'OrderCredit' are defined as [OneToMany].
When I put this on the testserver, and try to access the 'OrderObject' object of the loaded OrderCredit, I get the error:
NHibernate.LazyInitializationException: Initializing[.OrderObject#5496522]-Could not initialize proxy - no Session.
Code that fails:
Log.Debug(oc.OrderObject.Name);
Code that works:
Log.Debug(oc.Id);
This happens for any object that's part of the OrderCredit, but I am able to access the property fields of the OrderCredit (for instance the OrderCredit.Id).
Also, when I access any of the objects BEFORE I return the data to the original function calling the method, then it does cache the information or so, as I can access it then.
I've read a lot about this problem, like turning off Lazy, but that did not work for me either (or I did that on the wrong place).
The thing that frustrates me most, is the fact that it actually does work on my local machine, and not on the testserver. What could I be doing wrong?
Any help is highly appreciated.
1st update:
I am using now a GenericDao, using the default method of loading 1 ordercredit. I use the following code to load 1 ordercredit by Id.
OrderCredit oc = GenericService.Load<OrderCredit>(Id);
The code that's inside the GenericDAO is the following, BUT it does not end or breaks the session, which means I am able to access the objects attached to the ordercredit:
[Transaction(TransactionPropagation.Supports, ReadOnly = true)]
public T Load<T>(long id) where T : ISaveableObject
{
var obj = Session.Load<T>(id);
return obj;
}
This is nearly the same code as I had in the function which I included earlier in this question.
I'm now really confused because I don't know what it could be that ends the session. I will work with it now as it works, but I want to change it later on, so I can use my function to call the entire collection and access them via a for each loop.
Currently, I use my 'getOrderCredits' function to get the list of OrderCredit objects, and in the foreach, I get the Id, and use the GenericDao.Load to get the actual item, and can access the objects and such. Of course this is not the way it should be and needs to be.
I'd be amazed if I get this solved.
This is a common problem people have when using NHibernate. It happens because:
You open a session
You load an entity from the database which references another entity
You close the session
You try to access a property on your referenced entity
NHibernate tries to lazily load the entity from the database using the same session that loaded the parent entity
The session is closed, so NHibernate throws exceptions like woah.
You have a few options here:
Keep your session open longer, preferably using something like the unit of work pattern, which will give you tighter control.
Eagerly load your referenced entities when you query:
In your case as spring is managing your transaction for you the 2nd option is probably the quickest/easiest solution.
var creditrules = Session.CreateCriteria(typeof(OrderCredit));
creditrules.Add(Restrictions.Eq("Id", ordercreditid))
.SetFetchMode("OrderObject", FetchMode.Eager);
This will load the OrderObject when you load the OrderCredit.

Suggestions on how to map from Domain (ORM) objects to Data Transfer Objects (DTO)

The current system that I am working on makes use of Castle Activerecord to provide ORM (Object Relational Mapping) between the Domain objects and the database. This is all well and good and at most times actually works well!
The problem comes about with Castle Activerecords support for asynchronous execution, well, more specifically the SessionScope that manages the session that objects belong to. Long story short, bad stuff happens!
We are therefore looking for a way to easily convert (think automagically) from the Domain objects (who know that a DB exists and care) to the DTO object (who know nothing about the DB and care not for sessions, mapping attributes or all thing ORM).
Does anyone have suggestions on doing this. For the start I am looking for a basic One to One mapping of object. Domain object Person will be mapped to say PersonDTO. I do not want to do this manually since it is a waste.
Obviously reflection comes to mind, but I am hoping with some of the better IT knowledge floating around this site that "cooler" will be suggested.
Oh, I am working in C#, the ORM objects as said before a mapped with Castle ActiveRecord.
Example code:
By #ajmastrean's request I have linked to an example that I have (badly) mocked together. The example has a capture form, capture form controller, domain objects, activerecord repository and an async helper. It is slightly big (3MB) because I included the ActiveRecored dll's needed to get it running. You will need to create a database called ActiveRecordAsync on your local machine or just change the .config file.
Basic details of example:
The Capture Form
The capture form has a reference to the contoller
private CompanyCaptureController MyController { get; set; }
On initialise of the form it calls MyController.Load()
private void InitForm ()
{
MyController = new CompanyCaptureController(this);
MyController.Load();
}
This will return back to a method called LoadComplete()
public void LoadCompleted (Company loadCompany)
{
_context.Post(delegate
{
CurrentItem = loadCompany;
bindingSource.DataSource = CurrentItem;
bindingSource.ResetCurrentItem();
//TOTO: This line will thow the exception since the session scope used to fetch loadCompany is now gone.
grdEmployees.DataSource = loadCompany.Employees;
}, null);
}
}
this is where the "bad stuff" occurs, since we are using the child list of Company that is set as Lazy load.
The Controller
The controller has a Load method that was called from the form, it then calls the Asyc helper to asynchronously call the LoadCompany method and then return to the Capture form's LoadComplete method.
public void Load ()
{
new AsyncListLoad<Company>().BeginLoad(LoadCompany, Form.LoadCompleted);
}
The LoadCompany() method simply makes use of the Repository to find a know company.
public Company LoadCompany()
{
return ActiveRecordRepository<Company>.Find(Setup.company.Identifier);
}
The rest of the example is rather generic, it has two domain classes which inherit from a base class, a setup file to instert some data and the repository to provide the ActiveRecordMediator abilities.
I solved a problem very similar to this where I copied the data out of a lot of older web service contracts into WCF data contracts. I created a number of methods that had signatures like this:
public static T ChangeType<S, T>(this S source) where T : class, new()
The first time this method (or any of the other overloads) executes for two types, it looks at the properties of each type, and decides which ones exist in both based on name and type. It takes this 'member intersection' and uses the DynamicMethod class to emil the IL to copy the source type to the target type, then it caches the resulting delegate in a threadsafe static dictionary.
Once the delegate is created, it's obscenely fast and I have provided other overloads to pass in a delegate to copy over properties that don't match the intersection criteria:
public static T ChangeType<S, T>(this S source, Action<S, T> additionalOperations) where T : class, new()
... so you could do this for your Person to PersonDTO example:
Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();
And any properties on both Person and PersonDTO (again, that have the same name and type) would be copied by a runtime emitted method and any subsequent calls would not have to be emitted, but would reuse the same emitted code for those types in that order (i.e. copying PersonDTO to Person would also incur a hit to emit the code).
It's too much code to post, but if you are interested I will make the effort to upload a sample to SkyDrive and post the link here.
Richard
use ValueInjecter, with it you can map anything to anything e.g.
object <-> object
object <-> Form/WebForm
DataReader -> object
and it has cool features like: flattening and unflattening
the download contains lots of samples
You should automapper that I've blogged about here:
http://januszstabik.blogspot.com/2010/04/automatically-map-your-heavyweight-orm.html#links
As long as the properties are named the same on both your objects automapper will handle it.
My apologies for not really putting the details in here, but a basic OO approach would be to make the DTO a member of the ActiveRecord class and have the ActiveRecord delegate the accessors and mutators to the DTO. You could use code generation or refactoring tools to build the DTO classes pretty quickly from the AcitveRecord classes.
Actually I got totally confussed now.
Because you are saying: "We are therefore looking for a way to easily convert (think automagically) from the Domain objects (who know that a DB exists and care) to the DTO object (who know nothing about the DB and care not for sessions, mapping attributes or all thing ORM)."
Domain objects know and care about DB? Isn't that the whole point of domain objects to contain business logic ONLY and be totally unaware of DB and ORM?....You HAVE to have these objects? You just need to FIX them if they contain all that stuff...that's why I am a bit confused how DTO's come into picture
Could you provide more details on what problems you're facing with lazy loading?

Categories