0

I want to map a many to may relationship using ONLY data annotations so this is my case.

Say I have the following table

Foo:
FooId int identity
FooName varchar(max) not null

Bar:
BarId int identity
BarName varchar(max) not null

FooBarRelationships
TheBarId int 
TheFooId int 

As you can see the junction table contains FK names different from source. In addition the name of the table is also different

My classes are as follows

[Table("Foo")]
public class Foo {
    [Key]
    public Int32 FooId { get; set; }
    public String FooName { get; set; }

    public IEnumerable<Bar> Bars { get; set; }
}

[Table("Bar")]
public class Bar { 
    [Key]
    public Int32 BarId { get; set; }
    public String BarName { get; set; }

    public IEnumerable<Foo> Foos { get; set; }
}

How should I modify my classes using data annotations in order to tell that the table FooBarRelationships is a junction table and TheBarId is the foreign key from Bar table and TheFooId is the foreign key from Foo table?

P.S.

Having navigation properties declared as IEnumerable<T>, not as ICollection<T> is essential.

I've tried to map it using the map class which looks as follows

public class BarMap : EntityTypeConfiguration<Bar> {
    public BarMap() {
        this.HasMany(t => t.Foos)
            .WithMany(t => t.Bars)
            .Map(m => {
                m.ToTable("FooBarRelationships");
                m.MapLeftKey("TheBarId");
                m.MapRightKey("TheFooId");
            });
    }
}

this gives me the following error.

The type arguments for method 'System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Bar>.HasMany<TTargetEntity> (System.Linq.Expressions.Expression<System.Func<Bar, ICollection<TTargetEntity>>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

If there is a way to resolve this error without changing the type IEnumeralbe<T> to ICollection<T>, it is also welcomed.

Oybek
  • 7,016
  • 5
  • 29
  • 49

2 Answers2

1

I don't think you ca use IEnumerable because entity framework needs object that can be assigned.

Are IEnumerable collection supported in EF 4.1 for mapping?

You should be attacking the problem from another angle.

last part:

you can use the InverseAttribute on both side of your collection to declare the many to many relationship.

[Table("Foo")]
public class Foo {
    [Key]
    public Int32 FooId { get; set; }
    public String FooName { get; set; }
    [InverseAttribute("Foos")]
    public ICollection<Bar> Bars { get; set; }
}

[Table("Bar")]
public class Bar { 
    [Key]
    public Int32 BarId { get; set; }
    public String BarName { get; set; }
    [InverseAttribute("Bars")]
    public ICollection<Foo> Foos { get; set; }
}
Community
  • 1
  • 1
lnu
  • 1,404
  • 1
  • 9
  • 25
  • Thank you for your reply. I restored ICollection and reorganized the solution in the way it doesn't break the intensions. Can you answer the first part of the question, about supplying tables metadata without using fluent api, just dataannotations? – Oybek Dec 09 '11 at 12:45
1

If you don't use fluent mapping you must use the name of junction table and its columns expected by default convention which should be something like: FooBars with columns Foo_FooId and Bar_BarId.

Also as mentioned in answer by @Inu IEnumerable is not supported - at least lazy loading proxies demand ICollection and I'm almost sure that it is global requirement (as mentioned in linked answer). Code first normally skips all IEnumerable properties from mapping. Even it it is somehow supported IEnumerable is just an interface and on behind there will be some class like Collection, HashSet or List so exposing enumerable will not restrict code using your entity to convert your navigation property to that collection class.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670