1

I have a Word model for a dictionary/thesaurus:

public class Word
{
    public virtual string Text { get; set; }
    public virtual IList<Word> Synonyms { get; set; }
    public virtual IList<Word> Antonyms { get; set; }
}

Where each Word has many Synonyms and Antonyms. Word has a mapping of:

public class WordMapping : ClassMap<Word>
{
    Id(x => x.Text);
    HasMany(x => x.Synonyms);
    HasMany(x => x.Antonyms);
}

In my controller, I have a simple lookup method for a word:

public ActionResult Word(string word)
{
    using (var session = MvcApplication.SessionFactory.OpenSession())
    {
        using (var transaction = session.BeginTransaction())
        {
            var result = session.QueryOver<Word>()
                                .Where(w => w.Text == word)
                                .SingleOrDefault();

            if(result == null)
                RedirectToAction("InvalidWord");

            ViewBag.Synonyms = result.Synonyms.Select(t => t.Text);
            ViewBag.Antonyms = result.Antonyms.Select(t => t.Text);

            return View(result);
        }
    }
}

When I print out the ViewBag collections in my view, they are both the same. They are some seemingly arbitrary selection of elements from both bags, but not the whole bags.

Update: Below is my code to commit the Words to the database, if that helps. When I print out words after the commit, all the synonyms are correct.

List<Word> words;
...
using (var session = MvcApplication.SessionFactory.OpenSession())
{
    // populate the database
    using (var transaction = session.BeginTransaction())
    {
        foreach (var word in words)
            session.Save(word);

        transaction.Commit();
    }
}

PrintWords(words);
Wesley Tansey
  • 4,555
  • 10
  • 42
  • 69

1 Answers1

3

Try using an identity column Id instead of the Text property:

public class Word
{
    public virtual int Id { get; set; }
    public virtual string Text { get; set; }
    public virtual IList<Word> Synonyms { get; set; }
    public virtual IList<Word> Antonyms { get; set; }
}

and then:

Id(x => x.Id);
Map(x => x.Text);
HasMany(x => x.Synonyms);
HasMany(x => x.Antonyms);

UPDATE:

Here's a full working example (using SQLite and a console application to simplify but similar techniques could be applied in your web application):

// Domain layer
public class Word
{
    public virtual int Id { get; set; }
    public virtual string Text { get; set; }
    public virtual IList<Word> Synonyms { get; set; }
    public virtual IList<Word> Antonyms { get; set; }
}

// Mapping layer
public class WordMapping : ClassMap<Word>
{
    public WordMapping()
    {
        Id(x => x.Id).UnsavedValue(0);
        Map(x => x.Text);
        HasMany(x => x.Synonyms).Cascade.AllDeleteOrphan();
        HasMany(x => x.Antonyms).Cascade.AllDeleteOrphan();
    }
}

// Data access layer
class Program : InMemoryDatabase
{
    static void Main(string[] args)
    {
        using (var p = new Program())
        {
            // save some dummy data into the database
            var word = new Word
            {
                Text = "myword",
                Synonyms = new[]
                {
                    new Word { Text = "synonym 1" },
                    new Word { Text = "synonym 2" },
                }.ToList(),
                Antonyms = new[]
                {
                    new Word { Text = "antonym 1" },
                }.ToList()
            };
            using (var tx = p.Session.BeginTransaction())
            {
                p.Session.Save(word);
                tx.Commit();
            }

            // and now let's query the database
            using (var tx = p.Session.BeginTransaction())
            {
                var result = p.Session
                              .QueryOver<Word>()
                              .Where(w => w.Text == "myword")
                              .SingleOrDefault();

                var synonyms = result.Synonyms.Select(t => t.Text).ToArray();
                Console.WriteLine("-- Synonyms --");
                foreach (var item in synonyms)
                {
                    Console.WriteLine(item);
                }

                var antonyms = result.Antonyms.Select(t => t.Text).ToArray();
                Console.WriteLine("-- Antonyms --");
                foreach (var item in antonyms)
                {
                    Console.WriteLine(item);
                }
            }
        }
    }
}

public abstract class InMemoryDatabase : IDisposable
{
    private static Configuration _configuration;
    private static ISessionFactory _sessionFactory;

    protected ISession Session { get; set; }

    protected InMemoryDatabase()
    {
        _sessionFactory = CreateSessionFactory();
        Session = _sessionFactory.OpenSession();
        BuildSchema(Session);
    }
    private static ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .Database(SQLiteConfiguration.Standard.InMemory().ShowSql())
            .Mappings(M => M.FluentMappings.AddFromAssemblyOf<WordMapping>())
            .ExposeConfiguration(Cfg => _configuration = Cfg)
            .BuildSessionFactory();
    }

    private static void BuildSchema(ISession Session)
    {
        SchemaExport export = new SchemaExport(_configuration);
        export.Execute(true, true, false, Session.Connection, null);
    }

    public void Dispose()
    {
        Session.Dispose();
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Nope, still the same problem. – Wesley Tansey Feb 12 '11 at 09:46
  • @Darin, I get an error running that program: Could not create the driver from NHibernate.Driver.SQLite20Driver.Either way, I am doing almost everything exactly like you are in my actual program and it's still mixing the collections. When I actually build the dictionary from file, I print out the synonyms/antonyms and they're correct. – Wesley Tansey Feb 12 '11 at 10:40
  • @Wesley Tansey, in my example I am using SQLite, so make sure you have referenced the `System.Data.SQLite.dll` assembly. – Darin Dimitrov Feb 12 '11 at 10:42
  • I installed SQLite and referenced it, but I still get the same error. – Wesley Tansey Feb 12 '11 at 11:11
  • @Wesley Tansey, are you running this on .NET 4.0? Also are you running this on a x64 OS? There are some caveats with it: http://stackoverflow.com/questions/2605490/system-data-sqlite-net-4/2605509#2605509 – Darin Dimitrov Feb 12 '11 at 11:12