多対多の関係を作成するとき、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; }
}
複数の多対多のリストがある場合、この方法は非常に長くなりますが、これを行うより良い方法はありますか?
現在、エンティティフレームワークコアは「より良い」ソリューションを提供していません。
ただし、ジャンクションテーブルがなくても必要なデータにアクセスできます。次の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);