views:

439

answers:

2

Hi! I'm getting the following error: "Can't figure out what the other side of a many-to-many should be." Team Entity:

public class Team : IEntity
{
    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Employee> Employee { get; set; }

    public Team()
    {
        Employee = new List<Employee>();
    }
}

Employee Entity:

public class Employee : IEntity
{
    public int Id { get; set; }

    public String LastName { get; set; }

    public string FirstName { get; set; }

    public IList<Team> Team { get; set; }

    public string EMail { get; set; }

    public Employee()
    {
        Team = new List<Team>();
    }
}

Team mapping:

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id);

        // column mapping
        Map(p => p.Name);

        // relationship mapping
        HasManyToMany<Employee>(m => m.Employee);
    }
}

Employee mapping:

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id);

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // relationship mapping
        HasManyToMany<Team>(m => m.Team);
    }
}

Nobody has an answer?

Edit: The error occurs on the following code:

public static ISessionFactory CreateSessionFactory()
{
    return Fluently.Configure()
        .Database(MsSqlConfiguration.MsSql2008
        .ConnectionString(c=>
            c.Database("Ariha")
            .TrustedConnection()
            .Server("localhost")
            ).ShowSql())
        .Mappings(m => m.FluentMappings
            .AddFromAssemblyOf<BookMap>()
            .AddFromAssemblyOf<MagazineMap>()
            .AddFromAssemblyOf<EmployeeMap>()
            .AddFromAssemblyOf<TeamMap>())
        .ExposeConfiguration(BuildSchema)
        .BuildSessionFactory();
}

edit: here the whole solution: http://rapidshare.com/files/309653409/S.O.L.I.D.Ariha.rar.html

A: 

Fluent NHibernate tries to determine what the other side of a many-to-many relationship is by looking at the entity names and the collection properties. I believe it's not working in your case because your collection properties aren't plural; try renaming your collections Employees and Teams respectively.

Another way is to manually set the many-to-many table name on both sides, as this will disable the prediction.

James Gregory
your first tip does not work. Still the same error. And what do you mean by setting the many-to-many table name on both sides? How can I do that?
Rookian
ah ok there is a table method. But it does not work. I added .Table("EmployeeTeam") on both classes, but the same error ocurrs.
Rookian
+2  A: 

Could you provide code that causes your error? I just tried your mappings and they seem to work fine (on fluent 1.0 RTM and NH 2.1.1 GA with an SQLite database), with a minor modification to your EmployeeMap (I have assumed the employee-team relationship is bidirectional, and as per documentation you need to mark one side as inverse).

 // relationship mapping
 HasManyToMany<Team>(m => m.Team).Inverse();

Of course if the employee-team relationship is not bidirectional, I would have thought you should be able to specify a different .Table(name) for each one - but I have not tested this and you seem to be getting different results anyway (hence why providing example code would be best)

I'd also add that I suspect Set semantics (instead of Bag) would be more appropriate for the Employee.Team and Team.Employee properties. (Irregardless, don't do anything that assumes order is preserved, there is no guarantee that it will be)

Suggested mapping and example:

 public class Team
 {
  public int Id { get; set; }
  public string Name { get; set; }
  public ICollection<Employee> Employee { get; set; }
  public Team() { Employee = new List<Employee>(); }
 }

 public class Employee
 {
  public int Id { get; set; }
  public String LastName { get; set; }
  public string FirstName { get; set; }
  public ICollection<Team> Team { get; set; }
  public string EMail { get; set; }
  public Employee() { Team = new List<Team>(); }
 }

 public class TeamMap : ClassMap<Team>
 {
  public TeamMap()
  {
   Not.LazyLoad();
   // identity mapping
   Id(p => p.Id);
   // column mapping
   Map(p => p.Name);
   // relationship mapping
   HasManyToMany<Employee>(m => m.Employee).AsSet();
  }
 }

 public class EmployeeMap : ClassMap<Employee>
 {
  public EmployeeMap()
  {
   Not.LazyLoad();
   // identifier mapping
   Id(p => p.Id);
   // column mapping
   Map(p => p.EMail);
   Map(p => p.LastName);
   Map(p => p.FirstName);
   // relationship mapping
   HasManyToMany<Team>(m => m.Team).Inverse().AsSet();
  }
 }

 [TestFixture]
 public class Mapping
 {
  [Test]
  public void PersistDepersist()
  {
   var fcfg = Fluently.Configure()
    .Database(SQLiteConfiguration.Standard.UsingFile("testdb.sqldb"))
    .Mappings(mc =>
    {
     mc.FluentMappings.Add(typeof (TeamMap));
     mc.FluentMappings.Add(typeof (EmployeeMap));
    })
    .ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(false, true, false));

   var sess = fcfg.BuildSessionFactory().OpenSession();


   var teams = Enumerable.Range(0, 4).Select(i => new Team() {Name = "Team " + i}).ToArray();
   var employees = Enumerable.Range(0, 10).Select(i => new Employee() {FirstName = "Employee " + i}).ToArray();

   teams[0].Employee = new List<Employee>() {employees[0], employees[3], employees[5]};
   teams[1].Employee = new List<Employee>() {employees[7], employees[2], employees[5]};
   teams[3].Employee = new List<Employee>() {employees[0], employees[8], employees[9]};

   foreach (var team in teams)
    foreach (var employee in team.Employee)
     employee.Team.Add(team);

   Console.WriteLine("Dumping Generated Team/Employees:");
   Dump(teams);
   Dump(employees);

   using (var t = sess.BeginTransaction())
   {
    foreach (var team in teams)
     sess.Save(team);
    foreach (var employee in employees)
     sess.Save(employee);
    t.Commit();
   }

   sess.Flush();
   sess.Clear();

   var teamsPersisted = sess.CreateCriteria(typeof (Team)).List<Team>();
   var employeesPersisted = sess.CreateCriteria(typeof (Employee)).List<Employee>();

   Assert.AreNotSame(teams, teamsPersisted);
   Assert.AreNotSame(employees, employeesPersisted);

   Console.WriteLine();
   Console.WriteLine();
   Console.WriteLine("Dumping Depersisted Team/Employees:");
   Dump(teamsPersisted);
   Dump(employeesPersisted);
  }

  private static void Dump(IEnumerable<Team> teams)
  {
   foreach (var team in teams)
    Console.WriteLine("Team: " + team.Name + " has members: " + string.Join(", ", team.Employee.Select(e => e.FirstName).ToArray()));
  }

  private static void Dump(IEnumerable<Employee> employees)
  {
   foreach (var employee in employees)
    Console.WriteLine("Employee: " + employee.FirstName + " in teams: " + string.Join(", ", employee.Team.Select(e => e.Name).ToArray()));
  }
 }
fostandy
I have solve the problem ... .AddFromAssemblyOf<BookMap>() .AddFromAssemblyOf<MagazineMap>() .AddFromAssemblyOf<EmployeeMap>() .AddFromAssemblyOf<TeamMap>())was wrong. I only have to use one of this methods ;) and also I had to make my properties virtual.
Rookian

related questions