Reputation: 1065
I have a funny feeling this is just my understanding of nHibernate and Fluent nHibernate.
I have a small console application which exports a schema based on a bunch of entity classes. Everything works great until I do this:
public virtual int UserId { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string Email { get; set; }
public virtual UserType UserType { get; set; }
public virtual Client Client { get; set; }
public virtual string UniqueIdentifier { get; set; }
public virtual IList<UserAttribute> UserAttributes { get; set; }
/** CODE IN QUESTION **/
public virtual string GetAttributeValue(string name)
{
var value = UserAttributes.FirstOrDefault(ua => ua.AttributeDefinition.AttributeName == name);
if (value != null)
return value.Value;
else
return string.Empty;
}
If I comment out the function, everything works great. Even if I just have the function return string.Empty, everything works. However, once I add back the line:
var value = UserAttributes.FirstOrDefault(ua => ua.AttributeDefinition.AttributeName == name);
Everything breaks with this error:
"The entity '<>c__DisplayClass1' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id)."
I am using auto mapping. What is the cause of this error? I understand the error normally, but it looks like it's failing on an anonymous class. Do I just have a bad misunderstanding about how this is all supposed to work together? I am definitely a nHibernate newbie, both in practice and in philosophy. I'd love to be enlightened!
Upvotes: 2
Views: 411
Reputation: 688
Though, @Firo answer above works, it does not seem to work when you have Linq queries within another Linq query. Example:
DataTable Dt = FillData();
EnumerableRowCollection<DataRow> MasterProfileRows = null;
IList<RecordOwner> OwnedRecs = new List<RecordOwner>();
OwnedRecs.Add(new RecordOwner { ForeignRecordKey = 100 });
MasterProfileRows = from x in dt.AsEnumerable()
where OwnedRecs.Any(y => y.ForeignRecordKey.ToString() == x.Field<object>("ProfileID").ToString())
select x;
To work around this, I added this into my override to check the number of occurrences of "__displayclass" in the FullName of the class and if its greater than 1, we ignore mapping it.
public override bool ShouldMap(Type type)
{
// there is a bug where the fluent automapper tries to automap anonymous types within a lambda. the !type.IsDefined(typeof(CompilerGeneratedAttribute), false) works around this issue
// except where there is a nest linq query.
// see:
// https://github.com/jagregory/fluent-nhibernate/issues/146
// http://stackoverflow.com/questions/11446155/fluent-nhibernate-not-generating-schema-correctly-on-function/11447966#11447966
// http://stackoverflow.com/questions/14268568/odd-error-building-fluentnh-configuration
// http://stackoverflow.com/questions/11446155/fluent-nhibernate-not-generating-schema-correctly-on-function/11447966
// ignore nested linq queries (linq queries within linq queries) because they cause the auto mapper to error out.
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("__displayclass", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if(reg.Matches(type.FullName).Count > 1)
return false;
return !type.IsDefined(typeof(CompilerGeneratedAttribute), false);
}
Upvotes: 0
Reputation: 30803
the lambda ua => ua.AttributeDefinition.AttributeName == name
generates an inner class to capture the name parameter. The automapper walks over every type and tries to map it and unfortunatly also picks up the compiler generated one.
You could implement an AutomappingConfiguration to exclude the compiler generated classes
class MyAutomappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return !type.IsDefined(typeof(CompilerGeneratedAttribute), false) && base.ShouldMap(type);
}
}
Upvotes: 6