【问题标题】:Updating records in a many to many relationship in Entity Framework在实体框架中更新多对多关系中的记录
【发布时间】:2020-10-15 21:04:29
【问题描述】:

在我的数据库中,我有两个表:Trucks 和 TruckTypes。许多卡车可以有许多卡车类型。我已经使用数据库设计器创建了我的模型,并且中间表(仅包含主键)已被忽略,我理解这是 EF 的默认行为:

当我检查模型时,似乎两者现在都有相应模型的 ICollection 似乎正在工作。当我尝试添加新项目或更新现有项目时出现问题。

目前我用这个更新我的记录:

using (var db = new Entities())
{
    var truckResult = from t in db.ant_Truck
                        where t.Id == model.Id
                        select t;

    var truck = truckResult.Single();

    truck.Name = model.Name;
    truck.ant_TruckType.Clear();
    foreach (var truckType in model.TruckTypes)
        truck.ant_TruckType.Add(new ant_TruckType()
        {
            Name = truckType.Name,
            Disabled = truckType.Disabled
        });
    truck.Disabled = model.Disabled;

    db.SaveChanges();
}

我想我理解这个问题:新的 ant_truckType 模型被添加为“新”而不是链接到“ant_truckType”表中的现有记录,但我仍然不确定如何链接它们。

我尝试创建另一个查询表的方法并尝试返回 ICollection<ant_truckType>,但这开始给我其他关于转换为 ICollection 的错误:

public ICollection<ant_TruckType> GetDbTruckTypesForTruck(ant_Truck truck)
{
    using (var db = new Entities())
    {
        var result = from tt in db.ant_TruckType
                        where tt.ant_Truck.Contains(truck)
                        select tt;

        var truckTypes = result.ToList() as ICollection<ant_TruckType>;

        return truckTypes;
    }
}

我不确定此时我是否正确地做事,因为我花了很长时间试图理解为什么这不起作用。尝试执行上述操作的最有效方法是什么?

提前致谢。

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

    卡车类型是一个参考列表,其中一辆卡车可以有许多卡车类型。为了简化引用,我可能会避免在 Truck Types 中添加 Trucks 集合。它仍然是多对多,但不是:

    .HasMany(x => x.TruckTypes)
    .WithMany(x => x.Trucks)
    

    ...使用关联的链接表配置,它将被简化为:

    .HasMany(x => x.TruckTypes)
    .WithMany()
    

    更新卡车上的 TruckTypes 时,您需要一组所有 TruckTypes 来引用,然后您可以将其拆分以确定需要添加和删除的类型:

    理想情况下,您的模型只需要发送应与卡车相关联的卡车类型 ID 列表。如果您要发送卡车类型,请添加一个步骤以获取您希望与卡车关联的相关 ID。

    using (var db = new Entities())
    {
        // Load our truck and eager load its TruckTypes.
        var truck = db.ant_Truck.Include(t => t.TruckTypes).Single(t => t.Id == model.Id);
        
        // TODO: Update truck fields ...
        
        // Load all truck types we will want to associate with this truck.
        // For smaller sets we can simply load add truck types.
        var truckTypes = db.ant_TruckType.Where(tt => model.TruckTypeIds.Contains(tt.Id)).ToList();
        
        var existingTruckTypeIds = truck.TruckTypes.Select(tt => tt.Id).ToList();
        var truckTypeIdsToRemove = existingTruckTypeIds.Except(model.TruckTypeIds);
        var truckTypeIdsToAdd = model.TruckTypeIds.Except(existingTruckTypeIds);
    
        var truckTypesToRemove = truck.TuckTypes.Where(tt => truckTypeIdsToRemove.Contains(tt.Id));
        var truckTypesToAdd = truckTypes.Where(tt => truckTypeIdsToAdd.Contains(tt.Id));
    
        foreach(var truckType in truckTypesToRemove)
            truck.TruckTypes.Remove(truckType);
        foreach(var truckType in truckTypesToAdd)
            truck.TruckTypes.Add(truckType);
    
        db.SaveChanges();
    }
    

    我们加载卡车并包含其当前的卡车类型,然后从数据库上下文中加载我们希望与卡车关联的所有卡车类型的引用。从那里我们对我们的卡车模型上的卡车类型 ID 进行简单的清单。从中我们可以使用Except 来确定需要从我们的卡车中删除并添加到卡车的卡车类型 ID。然后,这些生成的 ID 列表可以从我们的卡车类型(要删除)和装载的卡车类型(要添加)中获取参考。

    使用双向引用,您可能需要在各自的 TruckType 上遍历 Trucks 集合并从中删除或添加当前 Truck 的开销。当涉及到双向引用时,我建议避免使用它们,除非它们确实有必要/有帮助。您始终可以通过查询 Truck 的条件然后使用 SelectMany 提供 TruckTypes 来按卡车过滤卡车类型。

    【讨论】:

      猜你喜欢
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多