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
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
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
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.
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
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.
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)]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
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
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
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
[
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 keyupdate.NYMEXHistoryId = ReadProperty(NYMEXHistoryIdProperty);
update.EntityKey =
new System.Data.EntityKey("BelAirPricingEntities.NYMEXHistories", "NYMEXHistoryId", update.NYMEXHistoryId); // Foreign keys - NYMEXProductupdate.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
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
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
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
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
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
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
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
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 keyupdate.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 NYMEXProductSystem.Data.
EntityKey ek = manager.ObjectContext.CreateEntityKey("BelAirPricingEntities.NYMEXProducts", oldNYMEXProduct);update.NYMEXProductReference.EntityKey = ek;
//Attach the updated entitymanager.ObjectContext.Attach(update);
//Foreign key - new NYMEXProductupdate.NYMEXProductReference.EntityKey = manager.ObjectContext.CreateEntityKey(
"BelAirPricingEntities.NYMEXProducts", newNYMEXProduct);}
else{
// Foreign keys - NYMEXProductupdate.NYMEXProductReference.EntityKey =
new System.Data.EntityKey("BelAirPricingEntities.NYMEXProducts", "NYMEXProductId", ReadProperty(NYMEXProductIdProperty));manager.ObjectContext.Attach(update);
}
//Do rest of updates and save changesupdate.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
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
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
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
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
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
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
Copyright (c) Marimer LLC