web-dev-qa-db-ja.com

マップされた多対多の関係を持つエンティティの保存

多対多の関係を作成するとき、3つのエンティティを作成します。Car、Part、および両方のエンティティのリストを含むCarPartです。

アプリケーションのクライアント側では、多対多のオブジェクトを使用する必要なく、車のすべてのパーツに直接アクセスできるようにしたいと考えています。これを行うには、AutoMapperライブラリを使用します。

// 1. Use Resourse to hide entity information from client    
CreateMap<Part, PartResource>()

// 2. Convert many-to-many entity (CarPart) to a simple parts-list 
CreateMap<CarPart, PartResource>()
    .ForMember(pr => pr.Name, opt => opt.MapFrom(cp => cp.Name));

CreateMap<Car, CarResource>()
    .ForMember(cr => cr.parts, opt => opt.MapFrom(c => c.CarParts)) // parts is a list of PartResource

この構成を使用すると、クライアント側のすべての車にパーツのリストが表示されます。新しいCarを追加するときは、新しく作成したCarをサーバーに送り返して、そのパーツリストをループし、手動で多対多のエンティティ(CarPart)を作成して保存します。

public async Task<CarResource> Post([FromBody] CarResourse resource) 
{
    var car = mapper.Map<CarResource, Car>(resource);
    await context.Cars.AddAsync(car);

    context.SaveChanges(); // car.Id is needed when creating the many-to-many entity

    foreach (var partResource in resource.Parts)
    {
        var carPart = new CarPart(car.Id, partResource.Id);

        await context.CarParts.AddAsync(carPart);
    }

    context.SaveChanges();

    return mapper.Map<Car, CarResource>(car);
}

モデル:

public class Car
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<CarPart> CarParts { get; set; }
}

public class Part
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<CarPart> CarParts { get; set; }
}

public class CarPart
{
    public int CarId { get; set; }
    public Car Car { get; set; }
    public int PartId { get; set; }
    public Part Part { get; set; }
}

複数の多対多のリストがある場合、この方法は非常に長くなりますが、これを行うより良い方法はありますか?

1
Sam

現在、エンティティフレームワークコアは「より良い」ソリューションを提供していません。

ただし、ジャンクションテーブルがなくても必要なデータにアクセスできます。次の2つのクラスを取ってください(リストを変更したことに気付きました)。

public class Car
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Part> Parts { get; set; }
}

public class Part
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Car> Cars { get; set; }
}

これで、dbcontext(_db以下)とlinqを使用して、必要なデータにアクセスします。

車のパーツを入手(車のId = 1

_db.Car.Include(c => c.Parts).Where(c => c.Id == 1).Select(c => c.Parts);

パーツが入っている車を取得する(パーツのId = 3

_db.Part.Include(p => p.Cars).Where(p => p.Id == 3).Select(p => p.Cars);

車に特定の部分があるかどうかを確認(車のId = 1、パーツのId = 3

var partIds = _db.Car.Include(c => c.Parts)
                 .Where(c => c.Id == 1)
                 .Select(c => c.Parts.Id);
var hasPart = part.Contains(3);
1
Corey P