1

When developing a many-to-many relation I create 3 entities: Car, Part and a CarPart which contains the lists of both entities.

On the client-side of the application I want to be able to directly access all the Parts of the Car without the need to use the many-to-many objects, to accomplish this I use the AutoMapper library.

// 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

Using this configuration, every car on the client-side will have a list of Parts. When adding a new Car I'm sending the newly created Car back to the server to loop its Parts-list and manually create and store the many-to-many entities (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);
}

Models:

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

When having multiple many-to-many lists this method will get very long, are there better ways of doing this?

  • orm framework aren't made to be fast on persisting. Still what is the point of that line : await context.CarParts.AddAsync(carPart); ? Do you really need always to wait here ? I don't think so. Note that I don't know about entity framework but on the ORM I use, you don't always need to declare a Many to Many dedicated entity, unless there is some additional fields. – Walfrat Jul 3 '17 at 11:23
  • The official EntityFramework Core documentation informs us that: Many-to-many relationships without an entity class to represent the join table are not yet supported. – Sam Jul 3 '17 at 11:34
  • Can we see how you have your models declared? Se here for a sample of how you could possibly achieve this. docs.microsoft.com/en-us/ef/core/modeling/relationships – Loren.Dorez Jul 5 '17 at 17:23
  • I've updated the answer with my models. The documentation that you've linked doesn't seem to give me the information that I'm looking for and is more about basic relationship creation. – Sam Jul 7 '17 at 12:42
1

Currently, entity framework core doesn't offer a "better" solution.

However, you can still access the data you want without the junction table. Take these two classes (Noticed I changed the lists):

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

Now you can use your dbcontext (_db below) along with linq, to access the data you want.

Get a car's parts (Car's Id = 1)

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

Get the cars a part is in (Part's Id = 3)

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

See if a car has a particular part (Car's Id = 1, Part's 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);
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.