0

I'm trying to create a

public class BaseMap<T> : ClassMap<T>

for my application. It should support localized entities, which their primary key must be both Id & Language:

CompositeId()
    .KeyProperty(x => x.Id)
    .KeyProperty(x => ((ILocalizedEntity)x).Language);

Another thing I want is one localized class to be able to reference another localized class.

I've done the following (After a lot of research, This is all I have):

    public new ManyToOnePart<TOther> References<TOther>(Expression<Func<T, TOther>> memberExpression) where TOther : BaseEntity
    {
        if (typeof(ILocalizedEntity).IsAssignableFrom(typeof(TOther)))
        {
            return base.References(memberExpression)
                .Columns("CategoryId")
                .Columns("Language");
        }

        return base.References(memberExpression);
    }

This gave me IndexOutOfRange exception when trying to insert, the reason was that the "Language" property was mapped twice, but there was only 1 language column in the DB, so I did this:

    public new ManyToOnePart<TOther> References<TOther>(Expression<Func<T, TOther>> memberExpression) where TOther : BaseEntity
    {
        if (typeof(ILocalizedEntity).IsAssignableFrom(typeof(TOther)))
        {
            return base.References(memberExpression)
                .Columns("CategoryId")
                .Columns("Language")
                .Not.Update()
                .Not.Insert();
        }

        return base.References(memberExpression);
    }

Which resolved the IndexOutOfRange problem, but didn't accomplished what I want. because it always inserts NULL to the column "CategoryId", because I specified Not.Insert() and Not.Update(), so it doesn't!

Now, I am in a situation I want it to map "CategoryId" but not "Language" because it's already mapped, as it's part of the ComposideId (primary key).

So I gave a try to this:

    public new ManyToOnePart<TOther> References<TOther>(Expression<Func<T, TOther>> memberExpression) where TOther : BaseEntity
    {
        if (typeof(ILocalizedEntity).IsAssignableFrom(typeof(TOther)))
        {
            return base.References(memberExpression)
                .Columns("CategoryId")
                .Nullable()
                .Columns("Language")
                .Not.Update()
                .Not.Insert();
        }

        return base.References(memberExpression);
    }

Whishing it will not insert or update only "Language" and not "CategoryId" - but no luck there either.

I've also tried to make language first in the PK:

            CompositeId()
                .KeyProperty(x => ((ILocalizedEntity)x).Language)
                .KeyProperty(x => x.Id);

And changed the Reference to:

            return base.References(memberExpression)
                .Columns("Language")
                .Not.Update()
                .Not.Insert()
                .Columns("CategoryId")
                .Nullable();

But still the "Not.Insert()" and "Not.Update()" is affecting both "Language" & "CategoryId".

I tried mapping the "CategoryId" before the "References" call, like this:

            Map(memberExpression, "Language");
            return base.References(memberExpression)
            .......

But it failed.

Anyone has any idea, how to reference a class with 2 columns CompositeId from a class with 2 columns CompositeId when 1 of the columns is common to the primary key and the foreign key?

Adam Tal
  • 5,911
  • 4
  • 29
  • 49
  • avoid compositeIds as much as possible. the following also avoids duplication http://stackoverflow.com/a/5431842/671619 – Firo Feb 14 '12 at 12:26
  • Still, If I want to use them, why must it be so complicated? If you think of what is right architecturally in the program and in the db, composite id sometimes is the best choice... isn't it? – Adam Tal Feb 16 '12 at 20:41

1 Answers1

0

i had a similar problem with a part of the compositeid being a reference and i couldn't resolve it either with google, SO nor trying on my own for 2 weeks, hence the dislike against them.

There are cases where CompositeId has its place but in the case you are describing most probably not. A simple dictionary and convenience properties to get the value for the actual language is much simpler and avoids duplicating all other properties which are the same for every language.

Firo
  • 30,626
  • 4
  • 55
  • 94
  • Are they really always the same for all languages? I dunno.... What i've tried to accomplish is applying the localization logic to every new entity... I just want it to inherit from an interface and let the magic be done.... If it weren't for that small technicality constraint.. – Adam Tal Feb 17 '12 at 11:47
  • 1
    some disadvantages: 1) you always need to know the language when you query by id 2) you always have to add the language to each query 3) you have to manage the id yourself (can't use existing idgenerators with compositeId) 4) Category.Color, Category.Type and the like would be duplicated for each language – Firo Feb 17 '12 at 11:59
  • 5) you have to reload the entity when switching language in your program 6) implement fallback if a localized entity is missing means you have to query the database again for the default language entity instead of having the default in the dictionary – Firo Feb 17 '12 at 13:37