DeepSave

Posts   
 
    
jackbauer
User
Posts: 12
Joined: 08-Oct-2008
# Posted on: 29-Oct-2008 14:17:07   

Hi Everybody!

I have a question i hope a simple one...

This is my made up example

-Contact Id (PK)(Identity) Name Tel

-Card Id(PK)(FK) CreatedBy

Is a 1:1 relation, the problem is when i try to save the contact the card don't save!

this is the code


ContactEntity oContact = new ContactEntity();
oContact.Name = "Jhon";
oContact.Tel = "000000";

CardEntity oCard = new CardEntity();
oCard.CreatedBy = "Me";

oContact.Card = oCard;

oContact.Save(true);

The code execute perfectly and the Contact is save but the card don't.

Thanks in advance!

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 29-Oct-2008 14:32:03   

Which runtime library version are you using?

Are contact & card in an inheritance hierarchy?

jackbauer
User
Posts: 12
Joined: 08-Oct-2008
# Posted on: 29-Oct-2008 15:13:49   

Walaa wrote:

Which runtime library version are you using?

Im Using LLBLGEN 2.6 June 6th 2008 Runtime 2.6.8.804 (i think)

Walaa wrote:

Are contact & card in an inheritance hierarchy?

No. there just two tables with the relationship. (SQL 2005)

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 29-Oct-2008 16:30:27   

Im Using LLBLGEN 2.6 June 6th 2008 Runtime 2.6.8.804 (i think)

Please download and use the latest release.

And then lets see if the problem still exists.

jackbauer
User
Posts: 12
Joined: 08-Oct-2008
# Posted on: 29-Oct-2008 21:08:13   

Hi Walaa,

I download the latest version and still the same.

I Add another Table to my example

-Contact ID (PK)(Identity) Name Tel

-Card ID(PK)(FK) CreatedBy

-Location ID(PK) Name ContactId (FK)

The Relation with Contact and Card is 1:1 Contact and Location is 1:M.

When i save a Contact like this


ContactEntity oContact = new ContactEntity();
oContact.Name = "Jhon";
oContact.Tel = "000000";

CardEntity oCard = new CardEntity();
oCard.CreatedBy = "Me";

oContact.Card = oCard;

LocationEntity oLocation = new LocationEntity();
oLocation.Name = "My Place";

oContact.Locations.Add(oLocation);

oContact.Save(true);


The Locations is saved but the Card don't. I double check everything but no idea what happen. I will keep looking.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 30-Oct-2008 07:51:40   

Could you please post the generated sql during the recursive save?

As we can't reproduce that, would be helpful if you attach some tiny repro solution so we can identify the specific problem.

David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 30-Oct-2008 10:04:10   

Also, be sure that you haven't hidden a relationship in the designer between these two entities.

Frans Bouma | Lead developer LLBLGen Pro
jackbauer
User
Posts: 12
Joined: 08-Oct-2008
# Posted on: 30-Oct-2008 13:10:32   

Hi Guys! Thanks for answer my question.

Otis wrote:

Also, be sure that you haven't hidden a relationship in the designer between these two entities.

I check that otis but is not hidden.

There's something that i don't know if could be that. I forgot to tell you in the first post. My process is like this.

- WebForm


ContactEntity oContact = new ContactEntity();
oContact.Name = txtName.Text;

LocationEntity oLocOne = new LocationEntity();
oLocOne.Name = ddlLocOne.SelectedValue;

LocationEntity oLocTwo = new LocationEntity();
oLocTwo.Name = ddlLocTwo.SelectedValue;

oContact.Locations.Add(oLocOne);
oContact.Locations.Add(oLocTwo);

oContact.Save(true);

Also i created another project for the validators, then i have this ContactValidator


[DependencyInjectionInfo(typeof(ContactEntity), "Validator")]
[Serializable]
public class ContactValidator : ValidatorBase
{

public override void ValidateEntityBeforeSave(IEntityCore involvedEntity)
{
ContactEntity oContact = involvedEntity as ContactEntity;;

//I generate a random code.
oContact.AuthCode = CreateAuthCode.Generate();

CardEntity oCard = new CardEntity();
oCard.CreatedBy = "Me";

oContact.Card = oCard;

base.ValidateEntityBeforeSave(involvedEntity);
}
}

I think maybe is because i add the card in the validator and then is not inserted. Could it be that?

Thanks Guys!!

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 30-Oct-2008 21:44:23   

Does it work correctly if you add the card to the contact outside of the validation routine ?

I seem to remember reading a previous post about validation not being the correct place to modify entity relationships, but I can't find it at the moment...

Could you also post the generated SQL with in both cases ?

jackbauer
User
Posts: 12
Joined: 08-Oct-2008
# Posted on: 01-Nov-2008 17:41:48   

Hi Everibody

MTrinder wrote:

Does it work correctly if you add the card to the contact outside of the validation routine ?

yes it's work perfect that way, but i want the Card to create on every contact i save, so i think the validator is the best place to put it, or not? stuck_out_tongue_winking_eye

this is the sql generated.

This one is when a Create the card inside the validator


declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Contacts] ([Name], [Tel], [AuthCode])  VALUES (@Name, @Tel, @AuthCode);SELECT @ContactId=SCOPE_IDENTITY()',N'@ContactId int output,@Name varchar(50),@Tel varchar(50),@AuthCode varchar(50)',@ContactId=@p3 output,@Name='Jack',@Tel='345345',@AuthCode='87687hjhkjhkjhk'
select @p3

declare @p3 int
set @p3=4
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Contacts] ([Name], [Tel], [AuthCode])  VALUES (@Name, @Tel, @AuthCode);SELECT @ContactId=SCOPE_IDENTITY()',N'@ContactId int output,@Name varchar(50),@Tel varchar(50),@AuthCode varchar(50)',@ContactId=@p3 output,@Name='Jack',@Tel='345345',@AuthCode='87687hjhkjhkjhk'
select @p3

declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My Place',@ContactId=4
select @p3

declare @p3 int
set @p3=3
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My Place',@ContactId=4
select @p3

declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My Apt',@ContactId=4
select @p3

declare @p3 int
set @p3=4
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My Apt',@ContactId=4
select @p3


This One is when i create the card on the webform


declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Contacts] ([Name], [Tel], [AuthCode])  VALUES (@Name, @Tel, @AuthCode);SELECT @ContactId=SCOPE_IDENTITY()',N'@ContactId int output,@Name varchar(50),@Tel varchar(50),@AuthCode varchar(50)',@ContactId=@p3 output,@Name='Bauer',@Tel='8874095',@AuthCode='87687hjhkjhkjhk'
select @p3

declare @p3 int
set @p3=5
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Contacts] ([Name], [Tel], [AuthCode])  VALUES (@Name, @Tel, @AuthCode);SELECT @ContactId=SCOPE_IDENTITY()',N'@ContactId int output,@Name varchar(50),@Tel varchar(50),@AuthCode varchar(50)',@ContactId=@p3 output,@Name='Bauer',@Tel='8874095',@AuthCode='87687hjhkjhkjhk'
select @p3

exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Cards] ([CardID], [CreatedBy])  VALUES (@CardId, @CreatedBy)',N'@CardId int,@CreatedBy varchar(50)',@CardId=5,@CreatedBy='me'

exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Cards] ([CardID], [CreatedBy])  VALUES (@CardId, @CreatedBy)',N'@CardId int,@CreatedBy varchar(50)',@CardId=5,@CreatedBy='me'

declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My SUV',@ContactId=5
select @p3

declare @p3 int
set @p3=5
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My SUV',@ContactId=5
select @p3

declare @p3 int
set @p3=NULL
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My dog',@ContactId=5
select @p3

declare @p3 int
set @p3=6
exec sp_executesql N'INSERT INTO [TestDB].[dbo].[Locations] ([Name], [ContactID])  VALUES (@Name, @ContactId);SELECT @LocationId=SCOPE_IDENTITY()',N'@LocationId int output,@Name varchar(50),@ContactId int',@LocationId=@p3 output,@Name='My dog',@ContactId=5
select @p3


Thank in advance!

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 03-Nov-2008 04:30:18   

Hi Jack,

I think the problem is that the ValidateEntityBeforeSave is called after the persist queue is built. So ValidateEntityBeforeSave is great when you change something on the involved entity but isn't when you are adding new entities to the formula.

So, the best thing to do is make your own method AddContact() that indeed creates the related CardEntity. Anyway, if you want to do that the way you are doing now, I recommend to use an Auditor. Here is an example:

using System;
using System.Collections.Generic;

using <YourProjectRoot>;
using <YourProjectRoot>.EntityClasses;
using SD.LLBLGen.Pro.ORMSupportClasses;


namespace <YourProjectRoot>.Auditors
{
    [DependencyInjectionInfo(typeof(ContactEntity), "AuditorToUse")]
    [Serializable]
    public class ContactAuditor : AuditorBase
    {
        // used to collect Card entities to attach
        private List<CardEntity> _CardEntitiesToAttach;

        public ContactAuditor()
        {
            _CardEntitiesToAttach = new List<CardEntity>();
        }

        public override void AuditInsertOfNewEntity(IEntityCore entity)
        {
            
            CardEntity Card = new CardEntity();
            // some other fields to set....
            Card.Contact = ((ContactEntity)entity);         

            _CardEntitiesToAttach.Add(Card);
        }

        public override System.Collections.IList GetAuditEntitiesToSave()
        {
            return _CardEntitiesToAttach;
        }

        public override void TransactionCommitted()
        {
            _CardEntitiesToAttach.Clear();
        }

    }
}

and here is the usage:

// create the contact
ontactEntity oContact = new ContactEntity();
oContact.Name = "Jhon";
oContact.Tel = "000000";

// you can automate this overriding the OnInitialize() method
oContact.AuditorToUse = new ContactAuditor();

// save the contact... and the card will be added to the transaction as well
oContact.Save(true);

Let me know if this work for you wink

David Elizondo | LLBLGen Support Team