EF4 CTP5 POCO не обновляет свойство навигации при сохранении - PullRequest
3 голосов
/ 05 января 2011

Я использую EF4 с объектами POCO, 2 таблицы выглядят следующим образом

Услуга ServiceID, Название, StatusID

Состояние StatusID, Имя

Объекты POCO выглядят так

Услуга ServiceID, Статус, Имя

Состояние StatusID, Имя

С состоянием Status для объекта Service, являющегося свойством навигации и типа Status.

В моем сервисном репозитории у меня есть метод save, который принимает сервисные объекты, присоединяет его к контексту и вызывает save. Это хорошо работает для службы, но если состояние этой службы было изменено, оно не обновляется. Мой метод сохранения выглядит следующим образом

public static void SaveService(Service service)
{
    using (var ctx = Context.CreateContext())
    {
        ctx.AttachModify("Services", service);
        ctx.AttachTo("Statuses",service.Status);
        ctx.SaveChanges();
    }
}

Метод AttachModify присоединяет объект к контексту и устанавливает его в измененном виде, он выглядит следующим образом

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);
}

Если я смотрю на профиль SQL, он даже не включает свойство навигации в обновлении для таблицы служб, он никогда не касается StatusID. Это сводит меня с ума. Любая идея, что мне нужно сделать, чтобы принудительно обновить свойство навигации?

Редактировать

Чтобы дать быстрый пример проблемы, вот быстрое консольное приложение, которое использует EF с моими объектами POCO для создания этой проблемы

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; }
}

Причина, по которой я не держусь за контекст, заключается в том, что в реальном приложении я пытаюсь использовать это на всем, что сделано в WCF автономно.

Ответы [ 2 ]

2 голосов
/ 07 января 2011

Эта проблема затягивалась, поэтому я решил найти решение, которым я не слишком доволен, но мне просто нужно было заставить его работать.

Мое решение заключалось в сохранении, чтобы повторно извлечь объекты из БД и использовать ApplyCurrentValues, чтобы обновить их, чтобы они соответствовали обновленным объектам POCO.

На основе моего примера в вопросе это решениеЯ использовал

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();
    }
}

Я действительно предпочел бы, чтобы это работало так, как это было закодировано в вопросе, так как я думаю, что это гораздо более удобное решение, так что если кто-то может улучшить это, пожалуйста, сделайте

0 голосов
/ 05 января 2011

Вы должны вручную установить состояние на Modified для каждой сущности, которую вы хотите обновить.Прикрепление объекта к контексту устанавливает его состояние Unchanged.Также вам не нужно прикреплять статус отдельно.Он уже связан с сервисом, потому что метод AttachTo присоединяет весь граф объекта.Вы также можете попробовать использовать Attach вместо AttachTo, но я не думаю, что это будет источником проблемы.

...