Entity Framework and LINQ to Lucene

Dec 7, 2009 at 10:12 AM
Edited Dec 7, 2009 at 10:30 AM

Hi,

I'm incorporating LINQ-Lucene into a project I'm working on, and having a minor issues with EF generated properties and Lucene. 

Basically, EF generates classes associated with tables in the database - nothing magic here. They're all partials (so can be extended happily), and can be decorated using [MetadataType] attributes. As an example, this is a basic user class:

 

[Document]
[MetadataType(typeof(UserMetaData))]
public partial class User : IIndexable, IHit
{
public int DocumentId{get;set;}
public float Relevance{get;set;}
}

public class UserMetaData
{
[Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(StandardAnalyzer), IsDefault = true)]
[DataType(DataType.EmailAddress)]
[Required(ErrorMessage = "An Email address is required.")]
[StringLength(256, ErrorMessage = "Email must be 256 characters or less.")]
[RegularExpression(RegexValues.EmailRegex, ErrorMessage = "Valid Email Address is required.")]
public string Email { get; set; }
}

 

The base framework itself contains the core part of the User object (for example, UserId entries, the actual definition of Email and such forth), whilst the decorations allow additional attributes to be added to EF generated objects - in this case I've got my validation hooked in, along with a [Field] statement to signify that it's a field that should be indexed.

I've been trying to get the Email property searchable in LINQ to Lucene - as a first cut to ensure everything is working before moving it to the whole project, but keep running across the following

"Unable to cast object of type 'System.Linq.Expressions.MemberExpression' to type 'Lucene.Linq.Expressions.FieldExpression'."

thrown from method VisitStartsWith in ParsingQueryTranslator.cs (line 89), from something as straightforward as

 

userIndex = new Index<User>(path);
var users = _serviceLayer.Data.Users.List(u=>!String.IsNullOrEmpty(u.Email)).Take(100).ToList();
userIndex.Add(users);
var query = (from u in userIndex where u.Email.StartsWith("b") select u);

Where users is a collection of User objects retrieved from a repository. The exception is thrown whenever the query is attempted to be used. My users are being added to the index, but for some reason the query being passed in isn't of the right type and I'm unsure how LINQ to Lucene should be handling it.

 

As a sanity check, I modified the user class to the following:

 

[Document]
[MetadataType(typeof(UserMetaData))]
public partial class User : IIndexable, IHit
{
public int DocumentId{get;set;}
public float Relevance{get;set;}

[Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(StandardAnalyzer), IsDefault = true)]
public string IndexEmail{ get { return Email; } set { Email = value; }}}

public class UserMetaData
{
[DataType(DataType.EmailAddress)]
[Required(ErrorMessage = "An Email address is required.")]
[StringLength(256, ErrorMessage = "Email must be 256 characters or less.")]
[RegularExpression(RegexValues.EmailRegex, ErrorMessage = "Valid Email Address is required.")]
public string Email { get; set; }
}


 

So Indexed email is a thin wrapper over the EF generated Email property, with the correct Field decoration. Changing the query accordingly -

 

var query = (from u in userIndex where u.IndexedEmail.StartsWith("b") select u);

 

.... and everything runs smoothly.?

Any ideas as to what needs modifying in order to get the System.Linq.Expressions.MemberExpression into a type of Lucene.Linq.Expressions.FieldExpression ? It's a pain to say the least, if I have to add indexable properties to each EF generated class - especially since it seems to be indexing entities correctly, just not able to query them afterwards.

Any thoughts or suggestions much appreciated, and if you've any questions please ask.

 

Thanks.

 

Ben

 

Dec 7, 2009 at 12:19 PM

Scratch that - pawing through the source code I found your [Document(MetadataType = typeof...)] - in my case, adding [Document(MetadataType=typeof(UserMetaData)] and it indexes and searches fine.

 

Ben

 

 

Dec 28, 2009 at 1:23 AM

I post another approch working with Entity Framework.

direct use EDM , not use ITable

read this post : Linq to Lucene for Entity Framework