Entity Framework Question

Entity Framework Question

Old forum URL: forums.lhotka.net/forums/t/7628.aspx


CyclingFoodmanPA posted on Tuesday, September 15, 2009

Ok, I have an object named NYMEXHistory, whose entity set name is NYMEXHistories.  It has a number of fields including one called NYMEXProductId which is tied to the named object NYMEXProduct, whose entity set name is NYMEXProducts.  I am having a problem executing an update on the NYMEXHistory object.  When I go to update the NYMEXProductId I am getting the error "Object reference not set to an instance of an object."

Here is what I have for code:

private void DataPortal_Update()
{
LastChangedBy = Csla.ApplicationContext.User.Identity.Name;
using (ObjectContextManager<BelAirPricingEntities> manager   =ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();
update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);
update.EntityKey =
new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId",   update.NYMEXHistoryId);
manager.ObjectContext.Attach(update);

update.NYMEXDate = ReadProperty(NYMEXDateProperty);
update.NYMEXProduct.NYMEXProductId = ReadProperty(NYMEXProductIdProperty);  <-- here is where the exception occurs.

update.ForwardDate = ReadProperty(ForwardDateProperty);
update.ForwardMonth = ReadProperty(ForwardMonthProperty);
update.NYMEXLow = ReadProperty(NYMEXLowProperty);
update.NYMEXHigh = ReadProperty(NYMEXHighProperty);
update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
update.LastChangedBy = ReadProperty(LastChangedByProperty);

manager.ObjectContext.SaveChanges();
}
}

Any ideas on how to do this would be helpfull.  Do I need to create a new NYMEXProduct object that is part of a NYMEXHistory object?  I tried that and it didn't work, but I think I am close to figuring it out.

Thanks in advance for your help.

CyclingFoodmanPA

 

lukky replied on Tuesday, September 15, 2009

Hi,

Does the related NYMEXProduct already exist in the database ? I think you'd have to first retrieve it into the context, and then you'd be able to associate it with the NYMEXHistory object.

If it doesn't exist, then you'd have to create it, and associate it.

By "associating" I really mean assigning. So you'd assign update.NYMEXProduct = theProduct; before trying to set its ID.

It's been a while since I played with EF, so I may be completely wrong Wink [;)]

regards

sergeyb replied on Tuesday, September 15, 2009

Update.NYMERXProduct is null.  You never populated it with any values.  It is not as straightforward process as one would like.  It will be improved in v2.0.  Now you have to create an instance of NUMEXProduct object, set its EntityKey, attach to context, then either attach (if not changed) “update” to it or set “update.NymexProduct” (if product ID changes) to the entity you created for NYMEXProduct.  I’d recommend buying a book on EF to make some of these pains go away.  This is only the first issue you will encounter in N-Tier EF implementations, but there will be more.

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Tuesday, September 15, 2009 10:45 AM
To: Sergey Barskiy
Subject: [CSLA .NET] Entity Framework Question

 

Ok, I have an object named NYMEXHistory, whose entity set name is NYMEXHistories.  It has a number of fields including one called NYMEXProductId which is tied to the named object NYMEXProduct, whose entity set name is NYMEXProducts.  I am having a problem executing an update on the NYMEXHistory object.  When I go to update the NYMEXProductId I am getting the error "Object reference not set to an instance of an object."

Here is what I have for code:

private void DataPortal_Update()
{
LastChangedBy = Csla.ApplicationContext.User.Identity.Name;
using (ObjectContextManager<BelAirPricingEntities> manager   =ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();
update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);
update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId",   update.NYMEXHistoryId);
manager.ObjectContext.Attach(update);

update.NYMEXDate = ReadProperty(NYMEXDateProperty);
update.NYMEXProduct.NYMEXProductId = ReadProperty(NYMEXProductIdProperty);  <-- here is where the exception occurs.

update.ForwardDate = ReadProperty(ForwardDateProperty);
update.ForwardMonth = ReadProperty(ForwardMonthProperty);
update.NYMEXLow = ReadProperty(NYMEXLowProperty);
update.NYMEXHigh = ReadProperty(NYMEXHighProperty);
update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
update.LastChangedBy = ReadProperty(LastChangedByProperty);

manager.ObjectContext.SaveChanges();
}
}

Any ideas on how to do this would be helpfull.  Do I need to create a new NYMEXProduct object that is part of a NYMEXHistory object?  I tried that and it didn't work, but I think I am close to figuring it out.

Thanks in advance for your help.

CyclingFoodmanPA

 



CyclingFoodmanPA replied on Tuesday, September 15, 2009

Hey Sergey,

Thanks for the response and I am getting closer.  I do have Julia Lerman's book, which is an excellent book and I am getting there, but I am getting a different error now.  For some reason EF thinks I am ADDING a relationship instead of modifying one.  Here is how I modified my code:

NYMEXProduct updateNYMEXProduct = new NYMEXProduct();
updateNYMEXProduct.EntityKey =
new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts",  
        "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));
update.NYMEXProduct = (NYMEXProduct)manager.ObjectContext.GetObjectByKey
       (updateNYMEXProduct.EntityKey);

Everything looks good in the update.NYMEXProduct variable.  However, when I run the SaveChanges(), I get an exception that reads as follows:
//? ex.Message
//"A relationship is being added or deleted from an AssociationSet 'FK_NYMEXProduct_NYMEXHistory'. With cardinality constraints, a corresponding 'NYMEXHistory' must also be added or deleted."

So, I am getting close :) but something is still missing.

 

 

sergeyb replied on Tuesday, September 15, 2009

You probably need to set History column in Products table (updateNYMEXProduct.NYMEXHistory) to satisfy this constraint.  Hard to tell without full code and model available.

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Tuesday, September 15, 2009 12:34 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: Entity Framework Question

 

Hey Sergey,

Thanks for the response and I am getting closer.  I do have Julia Lerman's book, which is an excellent book and I am getting there, but I am getting a different error now.  For some reason EF thinks I am ADDING a relationship instead of modifying one.  Here is how I modified my code:

NYMEXProduct updateNYMEXProduct = new NYMEXProduct();
updateNYMEXProduct.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts",  
        "NYMEXProductId"
, ReadProperty(NYMEXProductIdProperty));
update.NYMEXProduct = (NYMEXProduct)manager.ObjectContext.GetObjectByKey
       (updateNYMEXProduct.EntityKey);

Everything looks good in the update.NYMEXProduct variable.  However, when I run the SaveChanges(), I get an exception that reads as follows:
//? ex.Message
//"A relationship is being added or deleted from an AssociationSet 'FK_NYMEXProduct_NYMEXHistory'. With cardinality constraints, a corresponding 'NYMEXHistory' must also be added or deleted."

So, I am getting close :) but something is still missing.

 

 



CyclingFoodmanPA replied on Tuesday, September 15, 2009

Ok, I got it to work, but I had to read the record in again.  Here is the code I got to work:

[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Update()
{
LastChangedBy = Csla.
ApplicationContext.User.Identity.Name;
using (ObjectContextManager<BelAirPricingEntities> manager =
ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))
{
NYMEXHistory nh = (from oneNH in manager.ObjectContext.NYMEXHistories.Include("NYMEXProduct")
where oneNH.NYMEXHistoryId == this.NYMEXHistoryId
select oneNH).First();
if (this.IsDirty)
{
nh.ForwardDate = ReadProperty(ForwardDateProperty);
nh.ForwardMonth = ReadProperty(ForwardMonthProperty);
nh.NYMEXLow = ReadProperty(NYMEXLowProperty);
nh.NYMEXHigh = ReadProperty(NYMEXHighProperty);
nh.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
nh.LastChangedBy = ReadProperty(LastChangedByProperty);
NYMEXProduct updateNYMEXProduct = new NYMEXProduct();
updateNYMEXProduct.EntityKey =
new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));
nh.NYMEXProduct = (
NYMEXProduct)manager.ObjectContext.GetObjectByKey(updateNYMEXProduct.EntityKey);

manager.ObjectContext.SaveChanges();
}
}
}

Sergey, I was basing a lot on your RolodexEF example and you instantiated a new Companies object even for the update.  I couldn't get the update to work in the Rolodex because of some date error.  A buddy of mine were emailing back and forth and this is what I came up with and it worked.  However, is this the "correct solution" or is there a more correct one that I haven't found yet.

CyclingFoodmanPA

sergeyb replied on Tuesday, September 15, 2009

Yep, and you really do not want to do that.  What you need to do instead is create a History record based on some ID, and attach it to the context.  That way you do not need to round-trip to database during updates/inserts/deletes.

 

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Tuesday, September 15, 2009 1:10 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: Entity Framework Question

 

Ok, I got it to work, but I had to read the record in again.  Here is the code I got to work:

[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Update()
{
LastChangedBy = Csla.ApplicationContext.User.Identity.Name;
using (ObjectContextManager<BelAirPricingEntities> manager =
ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))
{
NYMEXHistory nh = (from oneNH in manager.ObjectContext.NYMEXHistories.Include("NYMEXProduct")
where oneNH.NYMEXHistoryId == this.NYMEXHistoryId
select oneNH).First();
if (this.IsDirty)
{
nh.ForwardDate = ReadProperty(ForwardDateProperty);
nh.ForwardMonth = ReadProperty(ForwardMonthProperty);
nh.NYMEXLow = ReadProperty(NYMEXLowProperty);
nh.NYMEXHigh = ReadProperty(NYMEXHighProperty);
nh.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
nh.LastChangedBy = ReadProperty(LastChangedByProperty);
NYMEXProduct updateNYMEXProduct = new NYMEXProduct();
updateNYMEXProduct.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));
nh.NYMEXProduct = (NYMEXProduct)manager.ObjectContext.GetObjectByKey(updateNYMEXProduct.EntityKey);

manager.ObjectContext.SaveChanges();
}
}
}

Sergey, I was basing a lot on your RolodexEF example and you instantiated a new Companies object even for the update.  I couldn't get the update to work in the Rolodex because of some date error.  A buddy of mine were emailing back and forth and this is what I came up with and it worked.  However, is this the "correct solution" or is there a more correct one that I haven't found yet.

CyclingFoodmanPA



CyclingFoodmanPA replied on Tuesday, September 15, 2009



Ok, I finally got it!  Here is what I finally had that worked:

[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Update()
{
      LastChangedBy = Csla.ApplicationContext.User.Identity.Name;
      using (ObjectContextManager<BelAirPricingEntities> manager =                     ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))
      {
        NYMEXHistory update = new NYMEXHistory();
        update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);
        update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

                // This is what did it and it has to be placed BEFORE the Attach!
                update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));

        manager.ObjectContext.Attach(update);

        update.NYMEXDate = ReadProperty(NYMEXDateProperty);
        update.ForwardDate = ReadProperty(ForwardDateProperty);
        update.ForwardMonth = ReadProperty(ForwardMonthProperty);
        update.NYMEXLow =  ReadProperty(NYMEXLowProperty);
        update.NYMEXHigh = ReadProperty(NYMEXHighProperty);
        update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
        update.LastChangedBy = ReadProperty(LastChangedByProperty);               

        int rowsAffected = manager.ObjectContext.SaveChanges();
      }
    }

Here is the link that finally got it to work and got the concept to sink in: Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:"Times New Roman"; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/cde2bb42-8978-4c18-bd52-e56814096881/

CyclingFoodmanPA


CyclingFoodmanPA replied on Thursday, September 17, 2009

Hmmm, I just discovered that the changes are not being saved to the database.  After I execute the
int rowsAffected = manager.ObjectContext.SaveChanges();
rowsAffected = 1, which is good, however, I query the DB in SQL Enterprise Manager and the value of NYMEXProduct has not changed.  Any ideas here!  And I thought I had things figured out :(.  Murphy has moved into EF!!

CyclingFoodmanPA

 

 

ajj3085 replied on Thursday, September 17, 2009

Do you have a transaction, and is it being committed?

CyclingFoodmanPA replied on Thursday, September 17, 2009

Hmmm, you are on to something.  The routine looks as follows:

[Transactional(TransactionalTypes.TransactionScope)]

private void DataPortal_Update()

{

LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

using (ObjectContextManager<BelAirPricingEntities> manager =

ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();

// NYMEXHistory key

update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);

update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

// Foreign keys - NYMEXProduct

update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));

manager.ObjectContext.Attach(update);

update.NYMEXDate = ReadProperty(NYMEXDateProperty);

update.ForwardDate = ReadProperty(ForwardDateProperty);

update.ForwardMonth = ReadProperty(ForwardMonthProperty);

update.NYMEXLow = ReadProperty(NYMEXLowProperty);

update.NYMEXHigh = ReadProperty(NYMEXHighProperty);

update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);

update.LastChangedBy = ReadProperty(LastChangedByProperty);

int rowsAffected = manager.ObjectContext.SaveChanges();

}

}

So it does have the attribute Transaction Transaction.Scope but I am basing my example on Sergey's RolodexEF and he is not doing anything after the update.  What should I be doing after the SaveChanges?

Thanks for the insight!

CyclingFoodmanPA

 

sergeyb replied on Thursday, September 17, 2009

You do not need to do anything else.  I’d put a breakpoint in the update to make sure the values that are put into EF object are correct.

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Thursday, September 17, 2009 11:52 AM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: Entity Framework Question

 

Hmmm, you are on to something.  The routine looks as follows:

[Transactional(TransactionalTypes.TransactionScope)]

private void DataPortal_Update()

{

LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

using (ObjectContextManager<BelAirPricingEntities> manager =

ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();

// NYMEXHistory key

update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);

update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

// Foreign keys - NYMEXProduct

update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));

manager.ObjectContext.Attach(update);

update.NYMEXDate = ReadProperty(NYMEXDateProperty);

update.ForwardDate = ReadProperty(ForwardDateProperty);

update.ForwardMonth = ReadProperty(ForwardMonthProperty);

update.NYMEXLow = ReadProperty(NYMEXLowProperty);

update.NYMEXHigh = ReadProperty(NYMEXHighProperty);

update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);

update.LastChangedBy = ReadProperty(LastChangedByProperty);

int rowsAffected = manager.ObjectContext.SaveChanges();

}

}

So it does have the attribute Transaction Transaction.Scope but I am basing my example on Sergey's RolodexEF and he is not doing anything after the update.  What should I be doing after the SaveChanges?

Thanks for the insight!

CyclingFoodmanPA

 



CyclingFoodmanPA replied on Thursday, September 17, 2009

Hey Sergey,

I am stepping through and it is putting the correct value into the (went from a 4 to a 5) update.NYMEXProductReferenct.EntitryKey and the rowsAffected = getting a 1 so something is happening, however, it is just not persisting to the DB for some reason.

I just went into the SQL Profiler and noticed the following SQL was executed:

exec sp_executesql N'update [dbo].[NYMEXHistory]
set [NYMEXDate] = @0, [ForwardDate] = @1, [ForwardMonth] = @2, [NYMEXLow] = @3, [NYMEXHigh] = @4, [NYMEXSettle] = @5, [LastChangedBy] = @6
where ([NYMEXHistoryId] = @7)
select [LastChanged]
from [dbo].[NYMEXHistory]
where @@ROWCOUNT > 0 and [NYMEXHistoryId] = @7',N'@0 datetime,@1 datetime,@2 int,@3 decimal(18,6),@4 decimal(18,6),@5 decimal(18,6),@6 varchar(8),@7 int',@0='2009-09-17 00:00:00:000',@1='2009-10-01 00:00:00:000',@2=1,@3=1.234500,@4=1.234500,@5=1.234500,@6='ksafford',@7=671840

It was not updating the NYMEXProductId in there.  Even though rowsAffected said 1, probably because the LastUpdated Timestamp was updated it knew it was updated.

CyclingFoodmanPA

sergeyb replied on Thursday, September 17, 2009

So, you are trying to update product ID, and that column is not updated?

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Thursday, September 17, 2009 12:40 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: RE: Entity Framework Question

 

Hey Sergey,

I am stepping through and it is putting the correct value into the (went from a 4 to a 5) update.NYMEXProductReferenct.EntitryKey and the rowsAffected = getting a 1 so something is happening, however, it is just not persisting to the DB for some reason.

I just went into the SQL Profiler and noticed the following SQL was executed:

exec sp_executesql N'update [dbo].[NYMEXHistory]
set [NYMEXDate] = @0, [ForwardDate] = @1, [ForwardMonth] = @2, [NYMEXLow] = @3, [NYMEXHigh] = @4, [NYMEXSettle] = @5, [LastChangedBy] = @6
where ([NYMEXHistoryId] = @7)
select [LastChanged]
from [dbo].[NYMEXHistory]
where @@ROWCOUNT > 0 and [NYMEXHistoryId] = @7',N'@0 datetime,@1 datetime,@2 int,@3 decimal(18,6),@4 decimal(18,6),@5 decimal(18,6),@6 varchar(8),@7 int',@0='2009-09-17 00:00:00:000',@1='2009-10-01 00:00:00:000',@2=1,@3=1.234500,@4=1.234500,@5=1.234500,@6='ksafford',@7=671840

It was not updating the NYMEXProductId in there.  Even though rowsAffected said 1, probably because the LastUpdated Timestamp was updated it knew it was updated.

CyclingFoodmanPA



CyclingFoodmanPA replied on Thursday, September 17, 2009

Correct.  Now, NYMEXDate and NYMEXProductId are set up as an index in the DB, but I don't think the EF has anything to do with that.  I could see in the debugger that the value was changing, but the SQL Profiler identified that the value was not being updated in the SQL created from the EF update.

CyclingFoodmanPA

CyclingFoodmanPA replied on Thursday, September 17, 2009

Ok, I FINALLY got things figured out and it is NOT pretty when you have to change a foreign key.  Here is my final code:
    [Transactional(TransactionalTypes.TransactionScope)]
    private void DataPortal_Update()
    {
      LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

      using (ObjectContextManager<BelAirPricingEntities> manager =
        ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))
      {
        NYMEXHistory update = new NYMEXHistory();
        // NYMEXHistory key
        update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);
        update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

        //Get old and new NYMEXProducts
        var oldNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == oldNYMEXProductId);
        var newNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == NYMEXProductId);
        //Check to see if it changed
        if (oldNYMEXProductId != NYMEXProductId)
        {       
          //Yep, a change was made, get the NYMEXProduct of the old NYMEXProductId and the EntityKey
          System.Data.EntityKey ek = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", oldNYMEXProduct);
          update.NYMEXProductReference.EntityKey = ek;        
        }

        //Attach the object
        manager.ObjectContext.Attach(update);

        //Again, check to see if it changed and if so, modify the entity key with the new NYMEXProduct
        if (oldNYMEXProductId != NYMEXProductId)
        {
          update.NYMEXProductReference.EntityKey = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", newNYMEXProduct);
        } 

        //Do rest of updates and save changes
        update.NYMEXDate = ReadProperty(NYMEXDateProperty);
        update.ForwardDate = ReadProperty(ForwardDateProperty);
        update.ForwardMonth = ReadProperty(ForwardMonthProperty);
        update.NYMEXLow =  ReadProperty(NYMEXLowProperty);
        update.NYMEXHigh = ReadProperty(NYMEXHighProperty);
        update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
        update.LastChangedBy = ReadProperty(LastChangedByProperty);      

        int rowsAffected = manager.ObjectContext.SaveChanges();          
      }
    }

Geeze, this is a real pain.  Not to mention, when I read the object in, I have to create a NYMEXProductId and an oldNYMEXProductId to see if anything changed to be able to compare and modify the NYMEXProductId.  I consider this a major hack.  I understand why things are more difficult because it is an actual relationship and not just a number in the table, but come on Microsoft.  I have hammered out lots of code in a few hours and it has taken me a couple of days to figure this out.  With some help from Sergey, my buddy Chris Russi and a few others who have responded to my posts. 

I just hope I made it easier for some other poor sucker to figure this out when they have to do it!!!

CyclingFoodmanPA

CyclingFoodmanPA replied on Thursday, September 17, 2009

Ok, I modified it so you only had to make the 2 fetches to the Db IF and ONLY IF, you changed the NYMEXProductId.  The code is as follows:

[Transactional(TransactionalTypes.TransactionScope)]

private void DataPortal_Update()

{

LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

using (ObjectContextManager<BelAirPricingEntities> manager =

ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();

// NYMEXHistory key

update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);

update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

//Check to see if it changed

//http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/de8db712-46d1-4d0d-8678-3f686575b574

//The above link is how I figured out how to do this

if (oldNYMEXProductId != NYMEXProductId)

{

//Get old and new NYMEXProducts

var oldNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == oldNYMEXProductId);

var newNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == NYMEXProductId);

//Foreign key - old NYMEXProduct

System.Data.EntityKey ek = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", oldNYMEXProduct);

update.NYMEXProductReference.EntityKey = ek;

//Attach the updated entity

manager.ObjectContext.Attach(update);

//Foreign key - new NYMEXProduct

update.NYMEXProductReference.EntityKey = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", newNYMEXProduct);

}

else

{

// Foreign keys - NYMEXProduct

update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));

manager.ObjectContext.Attach(update);

}

//Do rest of updates and save changes

update.NYMEXDate = ReadProperty(NYMEXDateProperty);

update.ForwardDate = ReadProperty(ForwardDateProperty);

update.ForwardMonth = ReadProperty(ForwardMonthProperty);

update.NYMEXLow = ReadProperty(NYMEXLowProperty);

update.NYMEXHigh = ReadProperty(NYMEXHighProperty);

update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);

update.LastChangedBy = ReadProperty(LastChangedByProperty);

int rowsAffected = manager.ObjectContext.SaveChanges();

}

}

Yes, I consider it a major hack and a real pain in the butt!  I am glad I figured it out, but I have much less hair now!

CyclingFoodmanPA

 

sergeyb replied on Thursday, September 17, 2009

You should not need to do those fetches.  You should be able to create Entity Keys without them.  I think code should look something like this:

System.Data.EntityKey ek = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", “NYMEXProductId”, NYMEXProductId);

Then you need to issue GetEntityByKey to make sure the product with this key is not in the context.  If not, you need to create new instance of NYMEXProduct, set its’ key to ek, then attach it to the context.  Same as getting it from DB, but no round-tripping involved.

 

 

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Thursday, September 17, 2009 3:20 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: RE: RE: Entity Framework Question

 

Ok, I modified it so you only had to make the 2 fetches to the Db IF and ONLY IF, you changed the NYMEXProductId.  The code is as follows:

[Transactional(TransactionalTypes.TransactionScope)]

private void DataPortal_Update()

{

LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

using (ObjectContextManager<BelAirPricingEntities> manager =

ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))

{

NYMEXHistory update = new NYMEXHistory();

// NYMEXHistory key

update.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);

update.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId);

//Check to see if it changed

//http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/de8db712-46d1-4d0d-8678-3f686575b574

//The above link is how I figured out how to do this

if (oldNYMEXProductId != NYMEXProductId)

{

//Get old and new NYMEXProducts

var oldNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == oldNYMEXProductId);

var newNYMEXProduct = manager.ObjectContext.NYMEXProducts.FirstOrDefault(c => c.NYMEXProductId == NYMEXProductId);

//Foreign key - old NYMEXProduct

System.Data.EntityKey ek = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", oldNYMEXProduct);

update.NYMEXProductReference.EntityKey = ek;

//Attach the updated entity

manager.ObjectContext.Attach(update);

//Foreign key - new NYMEXProduct

update.NYMEXProductReference.EntityKey = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", newNYMEXProduct);

}

else

{

// Foreign keys - NYMEXProduct

update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));

manager.ObjectContext.Attach(update);

}

//Do rest of updates and save changes

update.NYMEXDate = ReadProperty(NYMEXDateProperty);

update.ForwardDate = ReadProperty(ForwardDateProperty);

update.ForwardMonth = ReadProperty(ForwardMonthProperty);

update.NYMEXLow = ReadProperty(NYMEXLowProperty);

update.NYMEXHigh = ReadProperty(NYMEXHighProperty);

update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);

update.LastChangedBy = ReadProperty(LastChangedByProperty);

int rowsAffected = manager.ObjectContext.SaveChanges();

}

}

Yes, I consider it a major hack and a real pain in the butt!  I am glad I figured it out, but I have much less hair now!

CyclingFoodmanPA

 



CyclingFoodmanPA replied on Friday, September 18, 2009

Hmmm, to CreateEntityKey, you need the object so you have to make a call to the DB to get the object.  I have been battling with this for a few days and finally found something that works.  How would you use the GetEntityByKey?  I searched on msdn and there wasn't a whole lot out there to explain its useage.

The foreign key stuff is a real pain!  I was making great progress until I had to write code to change a FK.

CyclingFoodmanPA

 

sergeyb replied on Friday, September 18, 2009

Get entity by key would be done something like this:

 

public static T GetEntityByKey<T>(this ObjectContext context, string idColumnValue, string idColumnName, bool allowNulls) where T : EntityObject

        {

            T returnValue = null;

 

            System.Data.EntityKey typeKey = new System.Data.EntityKey(context.GetType().Name + "." + typeof(T).Name, idColumnName, idColumnValue);

 

            System.Data.Objects.ObjectStateEntry entry;

            if (!context.ObjectStateManager.TryGetObjectStateEntry(typeKey, out entry))

            {

 

And yes, foreign keys are bad in version 1.0.  Version 2.0 (.NET 4.0) should make things a lot easier.

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: CyclingFoodmanPA [mailto:cslanet@lhotka.net]
Sent: Friday, September 18, 2009 11:46 AM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: RE: RE: RE: Entity Framework Question

 

Hmmm, to CreateEntityKey, you need the object so you have to make a call to the DB to get the object.  I have been battling with this for a few days and finally found something that works.  How would you use the GetEntityByKey?  I searched on msdn and there wasn't a whole lot out there to explain its useage.

The foreign key stuff is a real pain!  I was making great progress until I had to write code to change a FK.

CyclingFoodmanPA

 



CyclingFoodmanPA replied on Tuesday, September 22, 2009

Finally, I have gotten my update to work at what I think is the most efficient method yet.  I have only 1 trip to the db and that is to acquire the record which is being changed, make the changes, and save it.  EF 1.0 is NOT friendly with Foreign Keys but after battling with it for a few days, I got things working.  Here is my final result:

    [Transactional(TransactionalTypes.TransactionScope)]
    private void DataPortal_Update()
    {
      LastChangedBy = Csla.ApplicationContext.User.Identity.Name;

      using (ObjectContextManager<BelAirPricingEntities> manager =
        ObjectContextManager<BelAirPricingEF.BelAirPricingEntities>.GetManager(DataConnection.BelAirPricingConnectionName, true))
      {
        NYMEXHistory update = (from oneNH in manager.ObjectContext.NYMEXHistories.Include("NYMEXProduct")
                               where oneNH.NYMEXHistoryId == NYMEXHistoryId
                               select oneNH).First();
        if (this.IsDirty)
        {
          update.NYMEXDate = ReadProperty(NYMEXDateProperty);

          //Update the EntityKey to NYMEXProduct
          update.NYMEXProductReference.EntityKey = new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));       

          update.ForwardDate = ReadProperty(ForwardDateProperty);
          update.ForwardMonth = ReadProperty(ForwardMonthProperty);
          update.NYMEXLow = ReadProperty(NYMEXLowProperty);
          update.NYMEXHigh = ReadProperty(NYMEXHighProperty);
          update.NYMEXSettle = ReadProperty(NYMEXSettleProperty);
          update.LastChangedBy = ReadProperty(LastChangedByProperty);
        }

        int rowsAffected = manager.ObjectContext.SaveChanges();
        LoadProperty(LastChangedProperty, update.LastChanged);
      }
    }

Hope this helps someone else battling with this concept.

CyclingFoodmanPA

 

Energiz0r replied on Friday, November 06, 2009

This helped me alot! I have been battling with this problem all morning, everything seemed to be working fine, no exceptions and no obvious problems..
Except that the data was not changed in the DB..

Thanks to CyclingFoodmanPA and Sergey for making this day much easier!

- Energiz0r -

Copyright (c) Marimer LLC