mapping unknown fields dynamically in fluent nhibernate

942 views
Skip to first unread message

Silvia

unread,
Jun 15, 2009, 8:10:26 PM6/15/09
to Fluent NHibernate

I have the below situation that I need help figure it out.
I am using fluent nhibernate with a legacy database. I need to map
some additional columns to a dictionary(?) property in my entity
dynamically, because I do not know the number of columns and column
names and other specifications at compile time and I dynamically need
to work with those columns(insert,update...).There is another object
which has those information and has a relationship with my main entity
based on the value of two other columns.Is this possible in
nhibernate?
I tried to use DynamicComponent but the problem is I don't know what
would be the properties in my component.
I have something like this:

In Entity.cs :
public virtual IDictionary AdditionalFields { get; set; }
public virtual Info AdditionalFieldsInfo{get; set;}

And in EntityMap.cs:
References(x => x.AdditionalFieldsInfo);
and I supposedly should have something like this:
DynamicComponent(x => x.AdditionalFields , m =>
{
m.Map(?Which I don't know how to map because I dont have the number of
columns to be mapped and column names.These information needs to come
from AdditionalFieldsInfo);
});

I also posted the question to nhusers group(nhu...@googlegroups.com)
but I still not very sure how to implement this.
I do appreciate if someone could help.
Thanks.
Silvia

Paul Batum

unread,
Jun 20, 2009, 8:45:37 AM6/20/09
to fluent-n...@googlegroups.com
Hi Silvia,

Can the column details be discovered at startup time? I'm thinking of something like this:


IList<string> dynamicColumns = GetCustomerColumns();
DynamicComponent(x => x.AdditionalFields, c =>
{
  foreach(string col in dynamicColumns)
  {
    string temp = col; // Avoid any modified closure issues.
    c.Map(x => (string)x[temp]);
  }
});

Paul Batum

rob

unread,
Jun 20, 2009, 11:11:46 AM6/20/09
to Fluent NHibernate
Funny...this is exactly my situation. See my post on Dynamic
components from a couple days ago. Unfortunately, this statement won't
work:
c.Map(x => (string)x[temp]);

because the variable temp isn't evaluated in the loop; the statement
is turned into an expression tree and evaluated later; at which time
"temp" won't exist. I've been trying all sorts of things the past few
days, and may be close to a solution involvoing manually building the
expression tree. Should know more on Monday. Keep me posted if you
figure something out!

On Jun 20, 8:45 am, Paul Batum <paul.ba...@gmail.com> wrote:
> Hi Silvia,
>
> Can the column details be discovered at startup time? I'm thinking of
> something like this:
>
> IList<string> dynamicColumns = GetCustomerColumns();
> DynamicComponent(x => x.AdditionalFields, c =>{
>   foreach(string col in dynamicColumns)
>   {
>     string temp = col; // Avoid any modified closure issues.
>     c.Map(x => (string)x[temp]);
>   }
>
> });
>
> Paul Batum
>

Pablo Ruiz

unread,
Jun 20, 2009, 11:32:40 AM6/20/09
to fluent-n...@googlegroups.com

private void SetupComponentParts(DynamicComponentPart<IDictionary> part)
{

   IList<string> dynamicColumns = GetCustomerColumns();
   foreach(string col in dynamicColumns)
   {
     string temp = col; // Avoid any modified closure issues.
     c.Map(x => (string)x[temp]);
   }
}

DynamicComponent(x => x.AdditionalFields, c => SetupComponentParts(c));


That's it..

James Gregory

unread,
Jun 20, 2009, 12:19:22 PM6/20/09
to fluent-n...@googlegroups.com
Rob: Just FYI, as far as I understand temp will still exist at the time because it's used within the closure. .Net imports that variable into the lambda's scope.

rob

unread,
Jun 20, 2009, 2:33:20 PM6/20/09
to Fluent NHibernate
Hmm..then my code should work too..i'll have to take a closer look on
Monday.

But.... I think what you're saying makes sense if you were invoking
the funcion declared in the lamda within the same scope; it would use
the temp variable declared in the loop. But, in this case, the
function is invoked in a different class (RefelectionHelper I
believe), and that class doesn't declare a variable called temp.
Also, I can't remember the code now, but I don't think fluent ever
invokes the funciotn declared by the lambda; it just examines the
expression tree to pull out properties for the purposes of generating
the mapping. And when it does, it won't know what to do w/ "temp".
Hopefully I'm wrong. :)

On Jun 20, 12:19 pm, James Gregory <jagregory....@gmail.com> wrote:
> Rob: Just FYI, as far as I understand temp will still exist at the time
> because it's used within the closure. .Net imports that variable into the
> lambda's scope.
>

Paul Batum

unread,
Jun 20, 2009, 7:05:29 PM6/20/09
to fluent-n...@googlegroups.com
Ahh yes, of course. Indeed, this expression from my code above is never executed:

(string)x[temp]

It is converted to an expression tree and inspected. The code that does this inspection is -very- basic, I can see how this won't work currently.

Maybe we should add a Map overload for dynamic components that just takes a string instead of a lambda expression?

rob

unread,
Jun 20, 2009, 7:35:43 PM6/20/09
to Fluent NHibernate
That would be great!!!

James Gregory

unread,
Jun 21, 2009, 4:21:54 AM6/21/09
to fluent-n...@googlegroups.com
+1 to that. The lambda map is hardly the most intuitive for dynamic components.

Hudson Akridge

unread,
Jun 21, 2009, 9:42:37 AM6/21/09
to fluent-n...@googlegroups.com
+1 here as well. Would solve some problems :)
--
- Hudson
http://www.bestguesstheory.com
http://twitter.com/HudsonAkridge

rob

unread,
Jun 22, 2009, 12:20:07 PM6/22/09
to Fluent NHibernate
Figured out how to work around this issue for now...

private Action<DynamicComponentPart<IDictionary>> mapping()
{

int i = 0;

return c =>
{
for (i = 0; i < 10; i++) // number of categories
{


string propertyName = "category" + i
Expression<Func<IDictionary, object>>
expression = Expression.Lambda<Func<IDictionary, object>>
(
Expression.Call(Expression.New(typeof
(Hashtable)),
typeof(IDictionary).GetProperty
("Item").GetGetMethod(),
new Expression[] { Expression.Constant
(propertyName, typeof(string)) }),
new ParameterExpression[]
{ Expression.Parameter(typeof(IDictionary), "dictionary") }
);
c.Map(expression, propertyName);
}
}
};
}

Paul Batum

unread,
Jun 29, 2009, 6:17:22 AM6/29/09
to fluent-n...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages