简体   繁体   中英

Entity Framework Many to Many List Table Association

I have the following classes (I am only showing the properties that matter):

public class TypeLocation
{
    [Key]
    public int Id {get; set;}
    public string Country {get; set;}
    public string State {get; set;}
    public string County {get; set;}
    public string City {get; set;}

    public List<Offer> Offers {get; set; }
    public TypeLocation()
    {
        this.Offers = new List<Offer>();
    }
}

public class Offer
{
    public int Id { get; set; }

    public ICollection<TypeLocation> LocationsToPublish { get; set; }
}

This creates the following in the database:

数据库架构

My Question/Problem

The TypeLocations table is prepopulated with a static list of country/state/county/city records, one or many of them can be associated with the Offer in LocationsToPublish property. When I try to add a location, using the following code, Entity Framework adds a NEW record in the TypeLocation table and then makes the association by adding a record in the OfferTypeLocations table.

    public static bool AddPublishLocation(int id, List<TypeLocation> locations)
    {
        try
        {
            using (AppDbContext db = new AppDbContext())
            {
                Offer Offer = db.Offers
                    .Include("LocationsToPublish")
                    .Where(u => u.Id == id)
                    .FirstOrDefault<Offer>();

                //Add new locations
                foreach (TypeLocation loc in locations)
                {
                    Offer.LocationsToPublish.Add(loc);
                }
                db.SaveChanges();
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

I don't want a new record added to the TypeLocations table, just a relational record creating an association in the OfferTypeLocations table. Any thoughts on what I am doing wrong?

Solution

Thanks to @Mick who answered below, I have found the solution.

    public static bool AddPublishLocation(int id, List<TypeLocation> locations)
    {
        try
        {
            using (AppDbContext db = new AppDbContext())
            {
                Offer Offer = db.Offers
                    .Include("LocationsToPublish")
                    .Where(u => u.Id == id)
                    .FirstOrDefault<Offer>();

                //Add new locations
                foreach (TypeLocation loc in locations)
                {
                    //SOLUTION
                    TypeLocation ExistingLoc = db.AppLocations.Where(l => l.Id == loc.Id).FirstOrDefault<TypeLocation>();

                    Offer.LocationsToPublish.Add(loc);
                }
                db.SaveChanges();
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

What happens is, using the existing AppDbContext, I retrieve an existing record from the TypeLocations table (identified here as AppLocations ) and then Add it to the LocationsToPublish entity.

The key is that I was to use the current AppDbContext (wrapped with the Using() statement) for all the work. Any data outside of this context is purely informational and is used to assist in the record lookups or creation that happen within the AppDbContext context. I hope that makes sense.

The TypeLocations are being loaded from a different AppDbContext, they are deemed new entities in the AppDbContext you're constructing within your method. To fix either:-

  1. Assuming the locations were detatched them from the instance of the AppDbContext outside of your method, you can attach these entities to the new context. OR
  2. Pass in the AppDbContext used to load the locations into your AddPublishLocation method.

I'd choose 2:-

public static bool AddPublishLocation(AppDbContext db, int id, List<TypeLocation> locations)
{
    try
    {
        Offer Offer = db.Offers
            .Include("LocationsToPublish")
            .Where(u => u.Id == id)
            .FirstOrDefault<Offer>();

        //Add new locations
        foreach (TypeLocation loc in locations)
        {
            Offer.LocationsToPublish.Add(loc);
        }
        db.SaveChanges();
        return true;
    }
    catch
    {
        return false;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM