Many to Many mapping not working - EF 4.1 RC

2019-04-03 03:02发布

问题:

UPDATE: After a bit more research it seems a number of my many-to-many mappings aren't working. Hmmm...

I'm upgrading a data access project from EF 4.1 CTP4 to EF 4.1 RC and I'm having trouble with the new EntityTypeConfiguration<T> setup.

Specifically I'm having an issue with a Many-to-Many relationship. I'm getting a Sequence contains no elements exception when I'm trying to get the .First() item.

The particular exception isn't really that interesting. All it's saying is that there are no items BUT I know there should be items in the collection - so there must be an issue with my new mappings.

Here's the code I have so far:

Product Model

public class Product : DbTable
{
    //Blah

    public virtual ICollection<Tag> Categories { get; set; }

    public Product()
    {
        //Blah
        Categories = new List<Tag>();
    }
}

BaseConfiguration

public class BaseConfiguration<T> : EntityTypeConfiguration<T> where T : DbTable
{
    public BaseConfiguration()
    {
        this.HasKey(x => x.Id);
        this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.Property(x => x.UpdatedOn);
        this.Property(x => x.CreatedOn);
    }
}

ProductConfiguration

public class ProductConfiguration : BaseConfiguration<Product> 
{
    public ProductConfiguration()
    {
        this.ToTable("Product");

        //Blah

        this.HasMany(x => x.Categories)
            .WithMany()
            .Map(m =>
            {
                m.MapLeftKey("Tag_Id");
                m.MapRightKey("Product_Id");
                m.ToTable("ProductCategory");
            });
    }
}

Previous CTP4 Mapping the worked!

this.HasMany(x => x.Categories)
    .WithMany()
    .Map("ProductCategory", (p, c) => new { Product_Id = p.Id, Tag_Id = c.Id  });

Can anyone see anything that needs fixing? Let me know if you want me to provide more code.

EDIT: More Code

DbTable

public class DbTable : IDbTable
{
    public int Id { get; set; }
    public DateTime UpdatedOn { get; set; }
    public DateTime CreatedOn { get; set; }
}

Tag

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Slug { get; set; }
    public bool Visible { get; set; }
    public virtual TagType TagType { get; set; }
}

TagConfiguration

public class TagConfiguration : EntityTypeConfiguration<Tag>
{
    public TagConfiguration()
    {
        this.ToTable("Tags");

        this.HasKey(x => x.Id);
        this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("tag_id");
        this.Property(x => x.Name).HasMaxLength(300).HasColumnName("tag_name");
        this.Property(x => x.Slug).HasMaxLength(500).HasColumnName("tag_slug");
        this.Property(x => x.Visible).HasColumnName("tag_visible");
        this.HasRequired(x => x.TagType).WithMany(tt => tt.Tags).Map(m => m.MapKey("tagtype_id"));
    }
}

Yes, this is a legacy database with naming conventions up to boohai.

I know the Tag class must be wired up correctly because Product has another property Specialization which is also mapped to Tag and it loads correctly. But do note that it's mapped in a one-to-many manner. So it seems to be the many-to-many with Tag.

I'll start checking out if any many-to-many associations are working.

回答1:

You need to specify both navigation properties to do many to many mapping.

Try adding the lambda in the WithMany property pointing back to the products:

this.HasMany(x => x.Categories)
            .WithMany(category=>category.Products)
            .Map(m =>
            {
                m.MapLeftKey(t => t.TagId, "Tag_Id");
                m.MapRightKey(t => t.ProductId, "Product_Id");
                m.ToTable("ProductCategory");
            });

(crossing fingers...)



回答2:

I haven't used the Code-First approach yet, but when working with POCOs I had to enable Lazy-Loading, to make Navigation Properties work. This is of course by design, but I don't know if you have to explicitly enable this behavior for Code-First.