I have master and detail table and its been defined as managed collection thru forward mapping. When I directly Save thru Object Scope, the master.pkfield automatically populated in Detail table on save. But if I use ObjectContainer and transfer new objects to Database thru CopyTo, on scope.commit I get exception that
Insert of '1400736671-' failed: Telerik.OpenAccess.RT.sql.SQLException: Cannot insert the value NULL into column 'TranNumb', table 'mydata.dbo.SalesDetail'; column does not allow nulls. INSERT fails.
The statement has been terminated.
at Telerik.OpenAccess.RT.Adonet2Generic.Impl.PreparedStatementImp.execute()
at OpenAccessRuntime.Relational.conn.PooledPreparedStatement.execute()
I used following Code.
oc.CopyTo(scope,
ObjectContainer.Verify.All);
Please guide what is missing.
Thanks.
10 Answers, 1 is accepted
I will be really thankful if anyone can reply on my following post regarding CopyTo method of Object Container not Transfering the Master Table's Primary key in Detail Table......
Thanks....
The problem arises when the AUTOINC identity generator is used. As the object container is not connected to the database, it is not able to obtain the id from there. You could avoid the problem by using the HIGHLOW key generator instead.
Hope that helps.
All the best,
Damyan Bogoev
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
I have also tested on Highlow and still having same problem as explained in my last post that problem is not related to keygeneration rather is about transfering master table Primary key to Child Table. Now Even I tried to put the value of Primary in Detail table manually still getting error. Following is the code, please advise
sm = persistenceService<SalesMater>.GetByPrimayKey(1); |
oc = new ObjectContainer();
|
IObjectCollector collector = new FetchGroupCollector(FetchGroupCollector.DeepFetchGroup); |
oc.CopyFrom(scope,sm.GetType().Name,sm,collector); |
oc.Transaction.Begin(); |
IList ilist = oc.NamedList(sm.GetType().Name); |
sm = (SalesMaster)ilist[0]; |
sm.CustomerId = 2; |
SalesDetail sd = new SalesDetail(); |
sd.ProductId = 1; |
sd.Qty = 1500; |
sd.Rate = 2000; |
sd.TranNumb = sm.TranNumb; //If I dont write this line, it is giving error Cannot insert the value NULL into column 'TranNumb' |
sm.SalesDetails.Add(sd); |
oc.Transaction.Commit(); |
scope.Transaction.Begin(); |
oc.CopyTo(scope, ObjectContainer.Verify.All); //error here after adding line sd.TranNumb = sm.TranNumb; |
scope.Transaction.Commit(); |
Error Message :
Telerik.OpenAccess.OpenAccessException was caught
Message="Unable to cast object of type 'Telerik.OpenAccess.RT.CopySM' to type 'DALTest.SalesMaster'."
Source="Telerik.OpenAccess"
CanRetry=false
StackTrace:
at Telerik.OpenAccess.SPI.Backends.ThrowException(Exception e)
at Telerik.OpenAccess.RT.ExceptionWrapper.Throw()
at OpenAccessRuntime.DataObjects.PCStateMan.handleException(Exception x)
at OpenAccessRuntime.DataObjects.PCStateMan.setIntField(PersistenceCapable _pc, Int32 field, Int32 currentValue, Int32 newValue)
at Telerik.OpenAccess.RT.CopySM.replacingIntField(PersistenceCapable pc, Int32 field)
at DALTest.SalesDetail.OpenAccessEnhancedReplaceField(Int32 )
at Telerik.OpenAccess.RT.CopySM.CopyTo(PersistenceCapable pc, Object[] _data, ObjectRepositoryMerger _m, StateManager onlineSm, Int32[] managedFields)
at Telerik.OpenAccess.RT.DisconnectedStateManager.Telerik.OpenAccess.SPI.OfflineStateManager.FillNewObject(PersistenceCapable pc, ObjectRepositoryMerger mrg, StateManager onlineSm)
at OpenAccessRuntime.DataObjects.PMProxy.updateFromCopy(PersistenceCapable pc, OfflineStateManager cpy, ObjectRepositoryMerger merger, Boolean isNew)
at Telerik.OpenAccess.RT.ContainerMerger.UpdateDestinationObject(ObjectMergeInfo info)
at Telerik.OpenAccess.RT.ObjectMerger.CopyObjectContent(ObjectMergeInfo info, IObjectMergerContext ctx)
at Telerik.OpenAccess.RT.ObjectMerger.UpdateObject(ObjectMergeInfo info, IObjectMergerContext ctx)
at Telerik.OpenAccess.RT.ContainerMerger.MergeList(ArrayList infos, Boolean avoidLoading, Boolean copyNew)
at Telerik.OpenAccess.RT.ContainerMerger.MergeAllNewChangedDeletedCleanHollow(Boolean forceResolve, ArrayList changes)
at Telerik.OpenAccess.RT.ContainerMerger.MergeAll(ArrayList changes)
at Telerik.OpenAccess.RT.ContainerMerger.Merge(ObjectContainer from, IObjectScope to, Hashtable conflicts, Exception e, ArrayList changes)
at Telerik.OpenAccess.ObjectContainer.CopyTo(IObjectScope objectScope, Verify verifyMode, ContainerMerger merger, ArrayList InternalChgSet)
at Telerik.OpenAccess.ObjectContainer.CopyTo(IObjectScope objectScope, Verify verifyMode, Boolean allFields)
at Telerik.OpenAccess.ObjectContainer.CopyTo(IObjectScope objectScope, Verify verifyMode)
at Data.Test`1.Save() in F:\TelerikTest\DataTest.cs:line 329
InnerException: System.InvalidCastException
Message="Unable to cast object of type 'Telerik.OpenAccess.RT.CopySM' to type 'DALTest.SalesMaster'."
Source="DALTest"
StackTrace:
at DALTest.SalesDetail.OpenAccessEnhancedReplaceField(Int32 )
at OpenAccessRuntime.DataObjects.PCStateMan.doRead(FieldMetaData fmd, Object oldValue)
at OpenAccessRuntime.DataObjects.PCStateMan.getObjectFieldImp(PersistenceCapable pc, FieldMetaData fmd, Object currentValue)
InnerException:
To achieve this you should do the following changes to the provided example:
1. The IObjectScope instance should be the same as the one that the 'sm' object lives in. To obtain it, use the following code:
sm = persistenceService<SalesMater>.GetByPrimayKey(1);
scope = Database.GetContext(sm)
as
IObjectScope;
2. When you retrieve the 'sm' object from the ObjectContainer's named list you should use the GetObjectById method:
sm = oc.GetObjectById(Database.OID.ParseObjectId(
typeof
(Order), 1))
as
SalesMaster;
3. Change the SalesDetails to unmanaged collection. Otherwise you would get a “Change of identity is not supported.” exception.
Now you could modify the SalesMaster record and insert a new SalesDetail.
Hope that helps.
Best wishes,
Damyan Bogoev
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
But by doing so I am also having problem when New SalesMaster Record is created and its child (salesDetail) added, then when I will get and Update the Master tables primary key to child object (salesdetail)..... I want to avoid this and would like to use manage collection, is there any other way.... or is it possible to set the collection handling type at runtime to either managed or unmanaged. ?
Thanks.
I found that same code is working when I just set the Parent Object in child instead of foreign key. Like
sd.salesMaster = sm;
Its working without any error and transfer Master table Primary key in detail table. But resultant Record is showing one more issue.
that ProductID is Null .... even I set sd.ProductId = 1;
using same solution to link the Product Object to SalesDetail.Product I did following
IObjectId oid = Database.OID.ParseObjectId(typeof(Product), sd.ProductId.ToString()); |
sd.Product = (Product)(Database.GetContext(bll.Current)).GetObjectById(oid); |
and It Saved.....
- Does this mean Object Container cannot translate foreign Key and need to set the Parent objects manually ?
- In above case if I use ProductId = 2, which was not loaded in Object Container (thru Salesmaster - Deepfetch...) then it save null in ProductId ..... Kindly guide how can this work..... Is there any way in Object Container, that it can fill the missing object that are refered automatically.....
Thanks
It seems that your issue comes from the fact that the desired product was not loaded in the object container.
The object container can resolve only those references to the objects that it was filled with. It can not resolve references to objects that are not part of the container as the container is designed for work in disconnected scenarios. That means that the container does not have direct access to the database for finding the missing records.
The code you have sent is not necessary actually as it assigns the product object which is resolved by the corresponding productId that is already assigned to the salesDetail object. If the product object existed, it would have been automatically resolved by OpenAccess since the id is already assigned to the salesDetail object.
All the best,
Zoran
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Working with managed collections in disconnected scenario is possible, but unlike in the connected one, you should mark the desired collection with the [ManagedInverse] attribute. Regarding the resolving of the foreign key references, this seems like a bug in the container when it copies the data back to the database and we will make sure that it is fixed in one of our future releases.
Nevertheless, if you have a web application scenario, I think your architecture should be scope based e.g. you should work in a connected fashion. Is there any specific reason why are you using the object container? It is originally designed for transporting persistent objects or serializing them in a disconnected location.
All the best,
Zoran
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.