I'm using EF4 with POCO objects the 2 tables are as follows
Service ServiceID, Name, StatusID
Status StatusID, Name
The POCO objects look like this
Service ServiceID, Status, Name
Status StatusID, Name
With Status on the Service object being a Navigation Property and of type Status.
In my Service Repository I have a save method that takes a service objects attaches it to the context and calls save. This works fine for the service, but if the status for that service has been changed it does not get updated. My Save method looks like this
public static void SaveService(Service service)
{
using (var ctx = Context.CreateContext())
{
ctx.AttachModify("Services", service);
ctx.AttachTo("Statuses",service.Status);
ctx.SaveChanges();
}
}
The AttachModify method attaches an object to the context and sets it to modified it looks like this
public void AttachModify(string entitySetName, object entity)
{
if (entity != null)
{
AttachTo(entitySetName, entity);
SetModified(entity);
}
}
public void SetModified(object entity)
{
ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
If I look at a SQL profile its not even including the navigation property 开发者_JS百科in the update for the service table, it never touches the StatusID. Its driving me crazy. Any idea what I need to do to force the Navigation Property to update?
Edit
To give a quick example of the problem heres a quick console app that uses EF with my POCO objects to produce this issue
static void Main(string[] args)
{
Service svc = GetService();
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
//Change and save Status
svc.Status = GetStatus("Stopped");
using (var ctx = new TestEFContext())
{
//Status is changed
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
ctx.AttachModify("Services", svc);
ctx.AttachTo("Statuses", svc.Status);
ctx.SaveChanges();
}
//Re-fetch service from db and check status
svc = GetService();
//Status is set back to its old value!!!!!!!!
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
Console.ReadLine();
}
private static Service GetService()
{
using (var ctx = new TestEFContext())
{
return ctx.Services.Include("Status").FirstOrDefault();
}
}
private static Status GetStatus(string name)
{
using (var ctx = new TestEFContext())
{
return ctx.Statuses.Where(n=>n.Name == name).FirstOrDefault();
}
}
public class Service
{
[DataMember] public int ServiceID { get; set; }
[DataMember] public string Name { get; set; }
[DataMember] public Status Status { get; set; }
}
public class Status
{
[DataMember] public int StatusID { get; set; }
[DataMember] public string Name { get; set; }
}
The reason I'm not holding on to the context is because in the real app I'm trying to use this on its all done in WCF in a disconnected way.
This problem was dragging on so I ended up going for a solution I'm not overlly happy with but I just needed to get it working.
My solution was on save to re-fetch the entities from the DB and use ApplyCurrentValues to update them to match the updated POCO objects.
Based on my example in the question this is the solution I used
static void Main(string[] args)
{
Service svc = GetService();
svc.Status = GetStatus("Stopped");
using (var ctx = new TestEFContext())
{
var svc2 = ctx.Services.Where(s=>s.ServiceID == svc.ServiceID).FirstOrDefault();
svc2.Status = ctx.Statuses.Where(n => n.StatusID == svc.Status.StatusID).FirstOrDefault();
ctx.ApplyCurrentValues("Services", svc);
ctx.SaveChanges();
}
}
I really would rather get it working the way it was coded in the question as I think that is a much neater solution so if anyone can improve on this please do
You must manually set state to Modified
for each entity you want to update. Attaching entity to context set its state to Unchanged
. Also you don't need to attach status separately. It is already attached with service because AttachTo
method attaches whole object graph. You can also try to use Attach
instead of AttachTo
but I don't think it will be source of the problem.
精彩评论