- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Polymorphic fetch and save 1:n relation
Joined: 10-Mar-2009
I am trying to save an entity object which has entity collection with a 1:n relationship. When I fetch the entity and prefetch the entity collection, the entity collection shows up as *_ (* being the name of the entity). I have not seen the underscore on any entity collection before. I assume this is because of the 1:n relationship? The fetch works fine. The problem I am having is with save after I fetch this entity. When I update the entity collection that is within the entity that I am saving, the save works fine (the first time). If I update it again right after, the save will fail. The error I get:
SD.LLBLGen.Pro.ORMSupportClasses.ORMConcurrencyException: During a save action an entity's update action failed. The entity which failed is enclosed. at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue(List`1 queueToPersist, Boolean insertActions, Int32& totalAmountSaved) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity(IEntity2 entityToSave, Boolean refetchAfterSave, IPredicateExpression updateRestriction, Boolean recurse) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity(IEntity2 entityToSave, Boolean refetchAfterSave) at Com.Ims.Cis.Cmt.CmtBl.Film.SaveMedia(IDataAccessAdapter adapter, String userId, Boolean saveMediaTranslations) in C:\Content\projects\trunk\ContentManagementTool\src\Com.Ims.Cis.Cmt.CmtBl\Film.cs:line 324 at Com.Ims.Cis.Cmt.CmtBl.Film.Save(String connectionString, String userId, Logger logger, Boolean saveMediaTranslations) in C:\Content\projects\trunk\ContentManagementTool\src\Com.Ims.Cis.Cmt.CmtBl\Film.cs:line 272
Why is this happening? Why does it work sometimes and not others? I am the only one using the database as the database is on my local development machine. So I am the only one connecting to the database. Is there something that I don't understand about the entity collections that end with an underscore (e.g. translations_)?
Here is my code for saving...
private void SaveMedia(IDataAccessAdapter adapter, string userId, bool saveMediaTranslations)
{
m_mediaEntity.Label = m_label;
m_mediaEntity.MediaType = MediaType.EntityObject;
m_mediaEntity.MediaVersionAttributes.EncodingLab = m_encodingLab == null ?
null : ((EncodingLab)m_encodingLab).GetEntityObject();
m_mediaEntity.MediaVersionAttributes.Licensor = m_licensor == null ?
null : ((Licensor)m_licensor).GetEntityObject();
m_mediaEntity.MediaVersionAttributes.Version = m_version == null ?
null : ((Version)m_version).GetEntityObject();
m_mediaEntity.MediaVersionAttributes.EncryptionType = m_encryptionType == null ?
null : ((EncryptionType)m_encryptionType).GetEntityObject();
SaveEncodedLanguages(adapter);
SaveSubtitleLanguage(adapter);
m_mediaEntity.LateWindowDate = m_lateWindowDate == null ?
new Nullable<DateTime>() : (DateTime)m_lateWindowDate;
m_mediaEntity.LicenseCategory = m_licenseCategory == null ?
null : ((LicenseCategory)m_licenseCategory).GetEntityObject();
m_mediaEntity.Created = IsUpdate() ?
m_mediaEntity.Created : DateTime.Now;
m_mediaEntity.Edited = DateTime.Now;
m_mediaEntity.UserId = userId;
m_mediaEntity.Title = m_title;
m_mediaEntity.Synopsis = m_synopsis;
m_mediaEntity.PrimaryGenre = m_primaryGenre == null ?
null : ((PrimaryGenre)m_primaryGenre).GetEntityObject();
m_mediaEntity.SecondaryGenre = m_secondaryGenre == null ?
null : ((SecondaryGenre)m_secondaryGenre).GetEntityObject();
m_mediaEntity.Rating = m_rating == null ?
null : ((Rating)m_rating).GetEntityObject();
m_mediaEntity.MediaVersionAttributes.RunTime = m_runtime == null ?
new Nullable<int>() : Convert.ToInt32(m_runtime);
if (saveMediaTranslations)
{
SaveMediaTranslations(adapter);
}
// This satisfies both update and save new functionality.
adapter.SaveEntity(m_mediaEntity, true);
}
private void SaveMediaTranslations(IDataAccessAdapter adapter)
{
adapter.DeleteEntityCollection(m_mediaEntity.MediaTranslation_);
m_mediaEntity.MediaTranslation_.Clear();
foreach (MediaTranslation translation in MediaTranslationCollection)
{
MediaTranslationEntity translationEntity = new MediaTranslationEntity();
translationEntity.Title = translation.Title;
translationEntity.Synopsis = translation.Synopsis;
translationEntity.Language = translation.Language.GetEntityObject();
m_mediaEntity.MediaTranslation_.Add(translationEntity);
}
}
Specs: .Net 3.5 Sql Server 2005 Windows XP Pro
Joined: 08-Oct-2008
I wouldn't get too hung up on the _'s. It's LLBLgen's way of making a name unique if there are any clashes and does not normally cause problems.
What you have sounds like a classic database locking issue. The sequence of actions you perform seems slightly unusual in that you are deleting the items from the collection first before creating and saving new ones...? Is there a specific reason for this ?
Are you starting a transaction in the code anywhere? If these deletes/saves all need to happen atomically then you should either use a transaction or a UnitOfWork to ensure that they succeed or fail as a unit.
Have you tried using the SQL tools (profiler/database activity monitor) to see what is going on at the DB end - it may give you a clue as to what is causing the issue.
Matt
Joined: 10-Mar-2009
MTrinder wrote:
I wouldn't get too hung up on the _'s. It's LLBLgen's way of making a name unique if there are any clashes and does not normally cause problems.
What you have sounds like a classic database locking issue. The sequence of actions you perform seems slightly unusual in that you are deleting the items from the collection first before creating and saving new ones...? Is there a specific reason for this ?
Are you starting a transaction in the code anywhere? If these deletes/saves all need to happen atomically then you should either use a transaction or a UnitOfWork to ensure that they succeed or fail as a unit.
Have you tried using the SQL tools (profiler/database activity monitor) to see what is going on at the DB end - it may give you a clue as to what is causing the issue.
Matt
The reason for deleting everything first is because it seems easier to remove everything from the reference table and then re add it. Instead of trying to compare and see if there are changes to update. On the UI side, the user is able to add new entities, remove entities and/or update entities. I found it easier to just re add everything to the database rather that compare all the changes.
Yes, I am using a transaction. I am unfamiliar with UnitOfWork. Can you point me to some documentation on this?
I will try using a profiler if my current test doesn't work. Currently I am trying to see if saving the reference table seperately (rather than doing a recursive save of the entity that contains the reference collection) will solve my problem.
Joined: 08-Oct-2008
UnitOfWork is described here. It's a way of batching up a set of entity actions that all need to be performed as a batch. It can handle saves and deletes of individual entites and entity collections so could suit your needs well.
You example sounds like the classic case of a transaction being left open at the end of the first process, and so causing locking issues the next time the process is run. That would be the first place to check
Matt
Joined: 10-Mar-2009
MTrinder wrote:
UnitOfWork is described here. It's a way of batching up a set of entity actions that all need to be performed as a batch. It can handle saves and deletes of individual entites and entity collections so could suit your needs well.
You example sounds like the classic case of a transaction being left open at the end of the first process, and so causing locking issues the next time the process is run. That would be the first place to check
![]()
Matt
Do you have to explicity close a transaction. I thought once a transaction is commited it is closed?
Joined: 10-Mar-2009
Walaa wrote:
Please use SQL Profiler or something similar to check what happens for the opened transaction.
Unfortunately I am using SQL Express and I don't think it has profiler. However, I was able to resolve my problem.
It seemed that there was a problem with entities I was deleting that needed to be re added. So I ended up comparing the new list of entities to the old list of entities and only deleting the entities removed. Then I updated the entities that were already in the list. And added entities that were new. It's a little bit more code, but it works. My guess is that the order in which the entities are being inserted/deleted/updated was causing problems, but I don't know what that order is. Wish I had profiler to figure that out.