21

我有两个具有相当标准的多对多关系的实体,它们是在 EF 5 Code First 中创建的。这些是服务和服务项目。Service 实体包含一个 ServiceItem 集合,ServiceItem 包含一个服务集合。我可以毫无问题地创建、更改数据并将数据保存到任一实体的基本属性。当我尝试将 ServiceItem 添加到 Service 或将 Service 添加到 ServiceItem 时,它似乎可以工作,但没有保存任何内容。我已经验证创建了所有正确的数据库表,包括带有交叉键的 ServiceItemService 表。添加项目时,数据库 ServiceItemService 表没有任何条目。没有错误,其他一切似乎都运行良好。

我有点难过,可以使用一些帮助。以下是课程。

服务类;

public class Service
{
    //Default constructor
    public Service()
    {
        //Defaults
        IsActive = true;
        ServicePeriod = ServicePeriodType.Monthly;
        ServicePeriodDays = 0;

        ServiceItems = new Collection<ServiceItem>();
    }

    public int ServiceID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public ICollection<ServiceItem> ServiceItems { get; set; }
    public string TermsOfService { get; set; }
    public ServicePeriodType ServicePeriod { get; set; }
    public int ServicePeriodDays { get; set; }
    public bool IsActive { get; set; }
}

ServiceItem 类;

public class ServiceItem
{
    public ServiceItem()
    {
        IsActive = true;
    }

    public int ServiceItemID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public ICollection<Service> Services { get; set; }
    public string UserRole { get; set; }
    public bool IsActive { get; set; }

}

这是我在尝试调试此问题时所做的 Fluent 映射。添加此映射之前和之后发生了相同的问题。

    public DbSet<Service> Services { get; set; }
    public DbSet<ServiceItem> ServiceItems { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Service>()
           .HasMany(p => p.ServiceItems)
           .WithMany(r => r.Services)
           .Map(mc =>
           {
               mc.MapLeftKey("ServiceItemID");
               mc.MapRightKey("ServiceID");
               mc.ToTable("ServiceItemService");
           });
    }

这是我用来保存 Service 项目的代码,该项目在 Service.ServiceItems 集合中包含 2-3 个 ServiceItems。我已仔细验证 ServiceItems 是否在正确的集合中。

                db.Entry(dbService).State = EntityState.Modified;
                db.SaveChanges();

dbService 对象似乎没有受到任何影响。ServiceItems 仍在正确的集合中,但没有对 ServiceItemService 数据库表进行更新。任何建议都会非常受欢迎。

-谢谢

4

1 回答 1

68

预计不会发生任何事情。

您要更改或添加的是实体ServiceServiceItem. 但是您不能通过将实体的状态设置为 来操纵关系Modified。这只会更新标量和复杂属性,但不会更新导航属性(= 关系)。(例如将Service实体的状态设置为ModifiedService.TitleService.Description等标记为已修改,并确保将这些属性保存到数据库中。但它不关心 的内容Service.ServiceItems。)

您可以通过将状态设置为来更改关系的唯一例外Modified外键关联。这些是在模型实体中公开了外键属性的关联,它们只能发生在一对多或一对一关联中。多对多关系始终是独立关联,这意味着它们永远不会在实体中具有外键属性。(因为 FK 在连接表中,但连接表不是实体,并且对模型类“隐藏”。)

有一种方法可以直接操纵多对多关联的关系,但它需要深入了解ObjectContextRelationshipManager- 在我看来 - 非常先进和棘手。

在多对多关联中添加和删除关系条目的通常且直接的方法是在实体附加到上下文时向集合添加项目和从集合中删除项目。EF 的更改跟踪机制将识别您所做的更改,并在您调用时生成相应的 INSERT、UPDATE 和 DELETE 语句SaveChanges

确切的过程取决于您是否还想保存Service和/或ServiceItem作为新实体,或者您是否只想添加现有实体之间的关系。这里有一些例子:

  • service应该插入,所有serviceItems 都应该插入,并且实体之间的关系也应该插入到连接表中:

    using (var context = new MyContext())
    {
        var service = new Service();
        var serviceItem1 = new ServiceItem();
        var serviceItem2 = new ServiceItem();
        service.ServiceItems.Add(serviceItem1);
        service.ServiceItems.Add(serviceItem2);
    
        context.Services.Add(service);
    
        context.SaveChanges();
    }
    

    添加对象图的“根”service就足够了,因为 EF 将识别图中的所有其他实体都未附加到上下文并假定它们必须插入到数据库中。

  • service已经存在并且不应该被插入,所有serviceItems 都应该被插入并且实体之间的关系也应该被插入到连接表中:

    using (var context = new MyContext())
    {
        var service = new Service { ServiceID = 15 };
        context.Services.Attach(service);
    
        var serviceItem1 = new ServiceItem();
        var serviceItem2 = new ServiceItem();
        service.ServiceItems.Add(serviceItem1);
        service.ServiceItems.Add(serviceItem2);
    
        context.SaveChanges();
    }
    

    EF 在此处识别(当SaveChanges被调用时)service已连接但其他实体未连接。没有 INSERTservice发生,但serviceItem1/2将与关系条目一起插入。

  • service已经存在并且不应该被插入,所有serviceItem的 s 已经存在并且不应该被插入,但是实体之间的关系应该被插入到连接表中:

    using (var context = new MyContext())
    {
        var service = new Service { ServiceID = 15 };
        context.Services.Attach(service);
    
        var serviceItem1 = new ServiceItem { ServiceItemID = 23 };
        context.ServiceItems.Attach(serviceItem1);
    
        var serviceItem2 = new ServiceItem { ServiceItemID = 37 };
        context.ServiceItems.Attach(serviceItem2);
    
        service.ServiceItems.Add(serviceItem1);
        service.ServiceItems.Add(serviceItem2);
    
        context.SaveChanges();
    }
    
  • 为了完整性:如何删除现有实体之间的关系?

    using (var context = new MyContext())
    {
        var service = context.Services
            .Include(s => s.ServiceItems) // load the existing Items
            .Single(s => s.ServiceID == 15);
    
        var serviceItem1 = service.ServiceItems
            .Single(s => s.ServiceItemID == 23); // query in memory, no DB query
        var serviceItem2 = service.ServiceItems
            .Single(s => s.ServiceItemID == 37); // query in memory, no DB query
    
        service.ServiceItems.Remove(serviceItem1);
        service.ServiceItems.Remove(serviceItem2);
    
        context.SaveChanges();
    }
    

    连接表中将服务 15 与 serviceItem 23 和 37 链接的两个关系行将被删除。

Attach或者,您可以从数据库中加载现有实体,而不是调用。它也将起作用:

var service = context.Services.Single(s => s.ServiceID == 15);

现有ServiceItem的 s 也是如此。

于 2012-12-31T13:59:28.277 回答