- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
TargetPerEntity - PK/FKs in objects
Joined: 02-Feb-2006
Hello,
I finally got a chance to try out LLBLGen's inheritance features, and I'm generating the objects using the TargetPerEntity option.
I am linking my tables as follows:
BaseObject SubTypeObject SomePKGUID ---> SomeFKGUID (PK on SubType)
Both PKs are showing up in my child object - is there a way to model the objects so that my child objects do not show the PK (afterall, the child PK should = the BaseObject's PK?)
Joined: 02-Feb-2006
mshe wrote:
Hello,
I finally got a chance to try out LLBLGen's inheritance features, and I'm generating the objects using the TargetPerEntity option.
I am linking my tables as follows:
BaseObject SubTypeObject SomePKGUID ---> SomeFKGUID (PK on SubType)
Both PKs are showing up in my child object - is there a way to model the objects so that my child objects do not show the PK (afterall, the child PK should = the BaseObject's PK?)
I changed both my base object and subtype object to have the same PK/FK name - this hides one of the keys.
but now when I submit data, I get the following error:
Message "An exception was caught during the execution of an action query: Cannot insert the value NULL into column 'RecordID', table MyDatabase.dbo.Record; column does not allow nulls. INSERT fails.
The statement has been terminated.. Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception." String
The ID is set correctly on the child object - but it is not saved to the parent object.
Here is the code I'm using: _Renewal = New RenewalEntity <--Derives from RecordEntity _Renewal.RecordId = Guid.NewGuid _Renewal.EntryDate = Now _Renewal.CampaignId = DialItem.CampaignId _Renewal.Refno = DialItem.Refno _Renewal.FirstName = DialItem.Fname
Any ideas? Does TargetPerEntity Inheritance only work with Int Identities? Seems a bit strange considering I'm manually setting the ID. I've tried setting the ID in the constructor but that does work either...
Thanks!
Joined: 02-Feb-2006
Otis wrote:
These should be supported. What are the runtime lib / designer build numbers?
Designer is November 6th. Runtime is 2.0.0.61107 November 7th.
I'm using SQL Server 2000.
I can send you my database script + project file if that'll help.
Joined: 02-Feb-2006
I created a new project + simplier database and the GUIDs work. So I remapped my current project and it still fails. I even reinstalled the latest download version of LLBLGen - no go.
Here is the hierachy:
Record (RecordID PK) + Renewal Entity (RecordID PK)
Here is the SQL debug log (notice how the Record table PK is not being set?):
Method Enter: DataAccessAdapterBase.SaveEntity(4) Active Entity Description: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Method Enter: DataAccessAdapterBase.DetermineActionQueues(7) Active Entity Description: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Method Enter: EntityCollectionBase2.Add Entity to Add Description: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Index of added entity: 0 Method Exit: EntityCollectionBase2.Add Method Enter: EntityCollectionBase2.Add Entity to Add Description: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Index of added entity: 0 Method Exit: EntityCollectionBase2.Add Entity added to insert queue: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Entity added to insert queue: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.FeeEntity. ObjectID: 42042f53-a20c-4326-bf96-66928e8fb0c9 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: AdComboFeeId. Type: System.Int32. Value: 5 Entity added to insert queue: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.FeeEntity. ObjectID: 5c93981c-682c-4afb-92e6-f3a99d16fbfc PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: AdComboFeeId. Type: System.Int32. Value: 3 Method Exit: DataAccessAdapterBase.DetermineActionQueues(7) Method Enter: DataAccessAdapterBase.PersistQueue Persistence action info: Action: Insert. Queue length: 3 Current persisted entity info: Entity: MultiVision.AutoTrader.DataLayer.EntityClasses.RenewalEntity. ObjectID: 011c6363-6689-46fa-89f0-86f3aea30e16 PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da PrimaryKey field: RecordId. Type: System.Guid. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da Method Enter: CreateInsertDQ Method Enter: CreateSingleTargetInsertDQ Generated Sql query: ** Query: INSERT INTO [WebDialer].[dbo].[Records] ([UserID], [EntryDate], [CampaignID], [Refno], [FirstName], [LastName], [Phone], [IsVerified], [IsOutstanding]) VALUES (@UserId, @EntryDate, @CampaignId, @Refno, @FirstName, @LastName, @Phone, @IsVerified, @IsOutstanding) Parameter: @UserId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 1000. Parameter: @EntryDate : DateTime. Length: 0. Precision: 23. Scale: 3. Direction: Input. Value: 12/4/2006 1:10:10 AM. Parameter: @CampaignId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 1. Parameter: @Refno : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 1000. Parameter: @FirstName : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "Speecheazy". Parameter: @LastName : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "MultiVision". Parameter: @Phone : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "4168162566". Parameter: @IsVerified : Boolean. Length: 0. Precision: 1. Scale: 0. Direction: Input. Value: False. Parameter: @IsOutstanding : Boolean. Length: 0. Precision: 1. Scale: 0. Direction: Input. Value: True.**
Method Exit: CreateSingleTargetInsertDQ Method Enter: CreateSingleTargetInsertDQ Generated Sql query: Query: INSERT INTO [WebDialer].[dbo].[Renewals] ([RecordID], [RegionCode], [Vehicle], [AdCode], [PrimaryRegionID], [PrimaryRegionCode], [SecondaryRegionID], [SecondaryRegionCode], [SizeID], [SizeCode], [PackageComboID], [PackageCode], [MagazineID], [MagazineCode], [AdPrice], [CCNumber], [CCMonth], [CCYear], [CCType]) VALUES (@RecordId, @RegionCode, @Vehicle, @AdCode, @PrimaryRegionId, @PrimaryRegionCode, @SecondaryRegionId, @SecondaryRegionCode, @SizeId, @SizeCode, @PackageComboId, @PackageCode, @MagazineId, @MagazineCode, @AdPrice, @Ccnumber, @Ccmonth, @Ccyear, @Cctype) Parameter: @RecordId : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: 5f930141-a164-4baf-9a7b-0cd1c28e12da. Parameter: @RegionCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "". Parameter: @Vehicle : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "abc". Parameter: @AdCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "030183514226". Parameter: @PrimaryRegionId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 8. Parameter: @PrimaryRegionCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "HAM". Parameter: @SecondaryRegionId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: -1. Parameter: @SecondaryRegionCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: <undefined value>. Parameter: @SizeId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 6. Parameter: @SizeCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "BBUYS". Parameter: @PackageComboId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 21. Parameter: @PackageCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "NONE". Parameter: @MagazineId : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: 6ab92e1d-a064-4c23-b7f9-44f23de6a24e. Parameter: @MagazineCode : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "AT". Parameter: @AdPrice : Currency. Length: 0. Precision: 19. Scale: 4. Direction: Input. Value: 124.12. Parameter: @Ccnumber : AnsiString. Length: 20. Precision: 0. Scale: 0. Direction: Input. Value: "44444444444444444444". Parameter: @Ccmonth : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 12. Parameter: @Ccyear : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 2006. Parameter: @Cctype : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "Visa".
Method Exit: CreateSingleTargetInsertDQ Method Exit: CreateInsertDQ Method Enter: DataAccessAdapterBase.ExecuteActionQuery Method Enter: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.ExecuteActionQuery Method Exit: DataAccessAdapterBase.SaveEntity(4) Method Enter: DataAccessAdapterBase.Rollback Method Enter: DataAccessAdapterBase.CloseConnection Method Exit: DataAccessAdapterBase.CloseConnection Method Enter: DataAccessAdapterBase.Reset Method Exit: DataAccessAdapterBase.Reset Method Exit: DataAccessAdapterBase.Rollback An exception was caught during the execution of an action query: Cannot insert the value NULL into column 'RecordID', table 'WebDialer.dbo.Records'; column does not allow nulls. INSERT fails. The statement has been terminated.. Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception.
Stack Trace at SD.LLBLGen.Pro.ORMSupportClasses.ActionQuery.Execute() at SD.LLBLGen.Pro.ORMSupportClasses.BatchActionQuery.Execute() at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.ExecuteActionQuery( IActionQuery queryToExecute) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue( ArrayList queueToPersist, Boolean insertActions) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity( IEntity2 entityToSave, Boolean refetchAfterSave, IPredicateExpression updateRestriction, Boolean recurse) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity( IEntity2 entityToSave) at Company.MyProject.Services.FormService.SaveRecord(RecordEntity Record) in D:\Multi-Vision\Projects\MyProject POS Dialer\Company.MyProject.Services\FormService.vb:line 72
Even tho I've manually set the RecordID - IsChanged flag = false...
- Record.Fields(0) {SD.LLBLGen.Pro.ORMSupportClasses.EntityField2} SD.LLBLGen.Pro.ORMSupportClasses.IEntityField2
- [SD.LLBLGen.Pro.ORMSupportClasses.EntityField2] {SD.LLBLGen.Pro.ORMSupportClasses.EntityField2} SD.LLBLGen.Pro.ORMSupportClasses.EntityField2 AggregateFunctionToApply None SD.LLBLGen.Pro.ORMSupportClasses.AggregateFunction Alias "RecordId_RecordEntity" String ContainingObjectName "RecordEntity" String
- CurrentValue {System.Guid} Object
- DataType {System.RuntimeType} System.Type DbValue Nothing Object ExpressionToApply Nothing SD.LLBLGen.Pro.ORMSupportClasses.IExpression FieldIndex 0 Integer IsChanged False Boolean IsForeignKey False Boolean IsNull False Boolean IsNullable False Boolean IsPrimaryKey True Boolean IsReadOnly False Boolean LinkedSuperTypeField Nothing SD.LLBLGen.Pro.ORMSupportClasses.IEntityFieldCore MaxLength 0 Integer Name "RecordId" String ObjectAlias "" String Precision 0 Byte Scale 0 Byte
As a workaround - I manually set:
Record.Fields(0).IsChanged = True
And it seems to save my entity. Very strange - any suggestions? Is there a reason why the baseObject RecordID is not being flagged as "IsChanged?"
What's odd is that the PK field of record isn't set to be changed... That's resulting in the absence of the field in the query. It does have a value, as you can see in the trace: the subtype has 2 PK field objects: one from the supertype and one of its own, both have the same value. So they are linked together. As the value is set, it should mark the field as changed...
Is record an abstract entity? If not, could you try to insert a record entity with a GUID pk value set? Is that resulting in the same results?
What's also odd is that as you say, it works with a new project created on a simpler db...
(edit) As expected (as your simpler test version also worked in your case), I can't reproduce it:
[Test]
public void SubTypeWithGuidPKSaveTest()
{
SubEntity toSave = new SubEntity();
toSave.Id = Guid.NewGuid();
toSave.Name = "Test";
toSave.Age = 10;
foreach(IEntityField2 field in toSave.Fields)
{
Assert.IsTrue(field.IsChanged);
Assert.IsNotNull(field.CurrentValue);
}
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
Assert.IsTrue(adapter.SaveEntity(toSave));
}
}
trace:
Method Enter: CreateInsertDQ
Method Enter: CreateSingleTargetInsertDQ
Generated Sql query:
Query: INSERT INTO [InheritanceOne].[dbo].[Super] ([ID], [Name]) VALUES (@Id_SuperEntity, @Name)
Parameter: @Id_SuperEntity : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: 5fc3058c-09f6-4ed7-af02-d0436fc78c84.
Parameter: @Name : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: "Test".
Method Exit: CreateSingleTargetInsertDQ
Method Enter: CreateSingleTargetInsertDQ
Generated Sql query:
Query: INSERT INTO [InheritanceOne].[dbo].[Sub] ([ID], [Age]) VALUES (@Id, @Age)
Parameter: @Id : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: 5fc3058c-09f6-4ed7-af02-d0436fc78c84.
Parameter: @Age : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 10.
Method Exit: CreateSingleTargetInsertDQ
Method Exit: CreateInsertDQ
1 succeeded, 0 failed, 0 skipped, took 1,75 seconds.
mshe wrote:
Hi Frans,
Yes the RecordEntity is marked as abstract. If you like, I can send you a copy of my database + project file + generated code.
The actual database isn't all that complex (only about 15 tables).
Send it to: support AT llblgen.com
Joined: 02-Feb-2006
Otis wrote:
mshe wrote:
Hi Frans,
Yes the RecordEntity is marked as abstract. If you like, I can send you a copy of my database + project file + generated code.
The actual database isn't all that complex (only about 15 tables).
Send it to: support AT llblgen.com
Hi Frans,
I found something interesting - the problem might be related to Remoting.
I'm using remoting to save my object.
On the client side - the object has the IsChanged flag set correctly... but once the object is sent via remoting to the server for saving... the IsChanged flag is set to false. (The XML has the IsChanged flag set to false...)
Perhaps it's an issue with the serialization of GUIDs + PKs?
Thanks.
When I serialize/deserialize the object using the binary formatter it indeed loses the ischanged flag. Very odd, as I have unittests which should trigger this and these succeed... I'll try to fix this.
(edit): found it. Fixed in runtimelibraries build 2.0.0.061205
Joined: 02-Feb-2006
Otis wrote:
When I serialize/deserialize the object using the binary formatter it indeed loses the ischanged flag. Very odd, as I have unittests which should trigger this and these succeed... I'll try to fix this.
(edit): found it. Fixed in runtimelibraries build 2.0.0.061205
Hi Frans,
Thank you for fixing the bug
P.S. will this fix the problem for XML (SOAP) serialization tool?
Which problem of the XML soap serialization? The Soap formatter is deprecated by ms and can't deal with generics as they found it wouldn't be helpful so they didn't build it in.
Joined: 02-Feb-2006
Otis wrote:
Which problem of the XML soap serialization? The Soap formatter is deprecated by ms and can't deal with generics as they found it wouldn't be helpful so they didn't build it in.
I noticed the IsChanged flag is set to false in the XML as well. I'm not sure if you had a different routine for serializing XML vs. Binary.
In anycase, you guys are so responsive in dealing with customer issues - I really appreciate that. I've been recommending LLBLGen left-right-and center to every collegue, person I talk to.
Thank again.
mshe wrote:
Otis wrote:
Which problem of the XML soap serialization? The Soap formatter is deprecated by ms and can't deal with generics as they found it wouldn't be helpful so they didn't build it in.
I noticed the IsChanged flag is set to false in the XML as well. I'm not sure if you had a different routine for serializing XML vs. Binary.
The bug was in the EntityField, it simply didn't respect the current state of the IsChanged flag, so if it was true and the value set in a given scenario didnt' change the value, the isChanged flag was reset. So this affected Xml serialization as well. You still see the flag being set to false in Xml with the new code as well?
In anycase, you guys are so responsive in dealing with customer issues - I really appreciate that. I've been recommending LLBLGen left-right-and center to every collegue, person I talk to. Thank again.
Thank you for your compliments!