There are tables: Products , Tags and ProductTags linking them
Models:
public class Product { public int Id { get; set; } public ICollection<Tag> Tags { get; set; } } public class Tag { public int Id { get; set; } public ICollection<Product> Products { get; set; } } Configuration:
public class TagConfiguration : EntityTypeConfiguration<Tag> { public TagConfiguration() { HasMany(tag => tag.Products) .WithMany(product => product.Tags) .Map(x => { x.ToTable("ProductTags"); x.MapLeftKey("TagId"); x.MapRightKey("ProductId"); }); } } You need to add a model of the link table, while maintaining the current navigation properties Tags { get; set; } Tags { get; set; } Tags { get; set; } and Products { get; set; } Products { get; set; } Products { get; set; } .
I add the model and its configuration:
public class ProductTags { public int ProductId { get; set; } public Product Product { get; set; } public int TagId { get; set; } public Tag Tag { get; set; } } public class ProductTagsConfiguration : EntityTypeConfiguration<ProductTags> { public ProductTagsConfiguration() { HasKey(p => new { p.ProductId, p.TagId }); ToTable("ProductTags"); } } After adding it starts to swear because of the same configurations:
One or more validation errors were detected during model generation:
TagProduct: Name: The EntitySet 'TagProduct' with schema 'dbo' and table 'ProductTags' is already defined. Each EntitySet must refer to a unique schema and table.
If you delete TagConfiguration , you will not be able to access the navigation properties. Replacing current properties with public ICollection<ProductTags> ProductTags { get; set; } public ICollection<ProductTags> ProductTags { get; set; } public ICollection<ProductTags> ProductTags { get; set; } does not fit.
Is it possible to make the configuration so that you can work with the intermediate model of ProductTags , and through the current navigation properties?
What is this solution for?
The code is written for the desktop application to the existing database. You need to filter by tags for selected products. If you do without a binding model, you will have to use ctx.Products.Where(...).Include(p => p.Tags).ToList() when getting the products. And since There may be several thousand products, this will be done slowly. If you enter the model of the linking table, you can get a list of links once, and then perform filtering already in memory.
We get all the tags and links when loading the program:
public readonly Dictionary<int, List<Tag>> ProductsAndTags = new Dictionary<int, List<Tag>>(); public void LoadProductsAndTags() { using (var context = new DbContext()) { var productsAndTags = context.ProductTags.AsNoTracking() .Include(x => x.Tag) .ToList(); foreach (var item in productsAndTags) { if (!ProductsAndTags.ContainsKey(item.ProductId)) ProductsAndTags.Add(item.ProductId, new List<Tag>()); ProductsAndTags[item.ProductId].Add(item.Tag); } } } Now you can get all the tags for each product very quickly:
if (Db.Tags.ProductsAndTags.ContainsKey(product.Id)) product.Tags = Db.Tags.ProductsAndTags[product.Id]; Why do I need to leave the existing navigation properties?
Now they are used in different parts of the program. If you refuse them, you will have to make a lot of changes.
The program will not develop further, with the exception of bugfixes, however, it is required to solve the issue of filtering by tags. And in order not to spend much time on this, it was decided to make such a decision head-on. I understand that it does not look right, but, unfortunately, I still do not see a better option.
ProductandTag, EF will add an intermediate table yourself, why are you trying to add it manually? There will naturally be a conflict. Why do you need to explicitly work with this intermediate table? Most likely there is a solution without using it explicitly; describe your task in more detail. - Andrey NOPProductpublic ICollection<Tag> Tags { get; set; }public ICollection<Tag> Tags { get; set; }public ICollection<Tag> Tags { get; set; }and from theTagproperty ispublic ICollection<Product> Products { get; set; }public ICollection<Product> Products { get; set; }public ICollection<Product> Products { get; set; }and use Linq in ram already? Or mark these properties with an attribute so that they are ignored by EF and fill them in manually if necessary. - Andrey NOP