1

Say I have the following models in my database:

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

    public string Content {get; set;}

    public List<Destination> Destinations {get; set;}

    public virtual Folder Folder {get; set;}

    public int FolderId {get; set;}
}

Now I want to add a new letter the client has made to my database:

public class SendLetterRequest
{
    public string Content {get; set;}

    public List<int> DestinationsIds {get; set;}
}

public void SaveLetterToDatabase(SendLetterRequest letter)
{
    var letterEntity = new LetterEntity 
    {
        Content = letter.Content;
        FolderId = 1;

        // How to insert the Destinations Ids in a way that I don't have to load all of those destinations to the context?
    }

    context.Set<LetterEntity>().Add(letterEntity);

    context.SaveChanges();
}

I know that if a LetterEntity only had a single Destination object I could just set it's foreign key value and the insert would work (Just like I do with the FolderId). How is it done when working with List of entities - how to tell EF that those Ids are already in the database, without fetching all of them to the context, so that it doesn't recreate them?

EDIT:

My Destination model -

public void Destination
{
    // Manual key
    public int Address {get; set;}

    public string DestinationName {get; set;}

    public string Information {get; set;}
}
10
  • Can you post your Destination entity model? Commented Mar 23, 2016 at 17:05
  • If you knew the order entities already existed on the DB and the foreign key points to the new entity then you could attach them and set the state to modified. Commented Mar 23, 2016 at 17:18
  • Added my Destination model. I know all the Addresses of the needed destinations. Attaching is possible only if I know all of the information of a Destination. Knowing only the Addresses means I have to fetch them from the database? Commented Mar 23, 2016 at 17:34
  • The thing is, you have a one-to-many (perhaps many-to-many) so the foreign key lies on the Destination side. Each Destination has a foreign key to a certain LetterEntity (again assuming one-to-many). It's impossible for LetterEntity to contain the foreign keys to each Destination. Commented Mar 23, 2016 at 17:47
  • It is indeed many to many. In that case, I have no choice but to load the fitting destinations and stick them to the letter? Commented Mar 23, 2016 at 17:50

1 Answer 1

2

Well, as you probably know, there are two ways to define many-to-many replationship in EF.

(1) Implicit link table

This is what you have used. You create explicitly only the two entitities, define the relation via navigation properties/and or model configuration and let EF maintain the so called "link" table. It's easy, but the downside is that you don't have access to that table, so the only way to add related items is to actually load the entities needed and add them to the navigation property collection.

(2) Explicit link table

Here you define explicitly the link entity and configure 2 one-to-many relations. This way you have access and can add related records w/o having the other entities loaded.

For instance, in your case it could be something like this:

Model:

public class LetterEntity
{
    public int Id { get; set; }
    // ....
    public List<LetterDestinationLink> Links { get; set; }
}

public class Destination
{
    public int Id { get; set; }
    // ....
    public List<LetterDestinationLink> Links { get; set; }
}

public class LetterDestinationLink
{
    [Key]
    [Column(Order = 0)]
    public int LetterId { get; set; }
    [Key]
    [Column(Order = 1)]
    public int DestinationId { get; set; }
    public LetterEntity Letter { get; set; }
    public Destination Destination { get; set; }
}

Context:

public class YourDbContext : DbContext
{
    public DbSet<LetterEntity> LetterEntities { get; set; }
    public DbSet<Destination> Destinations { get; set; }
    public DbSet<LetterDestinationLink> LetterDestinationLinks { get; set; }
}

Use case:

List<int> destinationIds = ...;
var letterEntity = new LetterEntity { ... };
letterEntity.Links = destinationIds.Select(destinationId =>
    new LetterDestinationLink { Letter = letterEntity, DestinationId = destinationId })
    .ToList();
context.Set<LetterEntity>().Add(letterEntity);
context.SaveChanges();
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you very much, great and well explained answer. I think I will leave the entities as they are now, don't want to change that. Is there a more efficient way to do this with an abstracted junction table? Attach the Destinations in some way? Otherwise I'll just load them as I do now.
Do you have them as object instances, or just Ids?
Just ids, in that case attaching will override all other data in the destinations, so I have to load them right?
Just get them with something like context.Destinations.Where(d => destinationIds.Contains(d.Id)).ToList()
Exactly what I did. Thanks a lot!!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.