Using score field with SolrNet - solr

I'm using SolrNet and have a problem where the score field is conflicting with documents being added or updated in the index.
The class representing my documents looks something like this
class MyDoc
{
[SolrUniqueKey("doc_id")]
public string DocId { get; set; }
[SolrField("foo")]
public string Foo { get; set; }
[SolrField("bar")]
public string Bar { get; set; }
[SolrField("score")]
public double Score { get; set; }
}
In the query being issued to Solr, I've added the 'score' field to the fl parameter, and the score value is returned and set correctly on this class. However, when adding or updating documents, I'm getting an error about the score field not existing in my index, which it doesn't, and shouldn't as this is a dynamic field.
The code doing the add/update is fairly simple:
Startup.Container.GetInstance<ISolrOperations<MyDoc>>().Add(doc);
It looks like I need the score property to be ignored by SolrNet (or Solr) when adding or updating documents, and only use it when retrieving documents.
Is there any way to achieve this?

I have accomplished this by having two separate classes. One that maps to documents being retrieved from the index as search results and another class that is used to add items to the index. So in this scenario you could do the following:
class MyDoc
{
[SolrUniqueKey("doc_id")]
public string DocId { get; set; }
[SolrField("foo")]
public string Foo { get; set; }
[SolrField("bar")]
public string Bar { get; set; }
}
class MyDocResult
{
[SolrUniqueKey("doc_id")]
public string DocId { get; set; }
[SolrField("foo")]
public string Foo { get; set; }
[SolrField("bar")]
public string Bar { get; set; }
[SolrField("score")]
public double Score { get; set; }
}
Be sure you initialize both classes pointing to the same solr url.
Startup.Init("http://localhost:8983/solr");
Startup.Init("http://localhost:8983/solr");
Then you can add with:
ServiceLocator.Current.GetInstance<ISolrOperations<MyDoc>>().Add(doc);
And Query with:
var solr ServiceLocator.Current.GetInstance<ISolrOperations<MyDocResult>>();
var results = solr.Query("foo bar");
You could also look into using the Dynamic or Fully Loose Mapping options for SolrNet if you do not want to create two separate classes.

If you make your POCO class have the Score as nullable you can use the same object for indexing and results
[SolrField("score")]
public double? Score { get; set; }

Related

Advanced NoSQL Query (RavenDB)

I'm trying to run a query that gets all of my references, but it isn't working.
What I have right now is
from UserGroups
where Id="ActionGroup"
select Accomplishments.ID, Accomplishments.Accomplish
But I need only the Accomplishments.Accomplish that belong in my other collection ActivityAccomplishments and these are nested in another object.
To be exact, I'm trying to figure out how to query the UserGroups collection and only look at the one with id="ActionGroup". After that I need all of the Accomplishments.Accomplish strings within the UserGroup list to be filtered out if they don't match a id in ActivityAccomplishment.
Basically, in the UserGroup I'm looking at it's List Accomplishments needs to filter out all strings within the Acc class that don't match an Id in ActivityAccomplishments. Can someone please help me.
Here are the classes I'm using.
public class UserGroups
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<Acc> Accomplishments { get; set; }
}
public class Acc
{
public string Id { get; set; }
public List<string> Accomplish { get; set; }
}
public class ActivityAccomplishments
{
public string Id { get; set; }
}
try this:
from UserGroups
where Id = "ActionGroup" AND Accomplishments[].Accomplish != "theIdYouDontWant"
select Accomplishments[].Accomplish as AccomplishStringsList
(not necessary to add the 'as AccomplishStringsList' - it is just a name for the results)

Displaying Specific Fields from Facebook Graph API JSON

I'm trying to simply display the list of members in a specific group using the Facebook Graph API. I'm using Newtonsoft.JSON.
Here is the results of my url query:
Graph API Results
I used a JSON class generator and it gave me this:
public class Datum
{
public string name { get; set; }
public string id { get; set; }
public bool administrator { get; set; }
}
public class Cursors
{
public string before { get; set; }
public string after { get; set; }
}
public class Paging
{
public Cursors cursors { get; set; }
}
public class Members
{
public List<Datum> data { get; set; }
public Paging paging { get; set; }
}
public class RootObject
{
public Members members { get; set; }
public string id { get; set; }
}
I've tried every combination I can think of to display simply the list of members in a multi-line text box, but not sure if this is even the best way to display the list on a Windows Form App.
Could someone help me understand 2 things.
1) What is the best component to display the list of names in a Windows Form App?
2) What is the 1 or 2 lines to generate just the list of names using JsonConvert.DeserializeObject from this?
My raw data is stored in: string responseFromServer = reader.ReadToEnd();
To deserialize the JSON into your classes:
RootObject obj = JsonConvert.DeserializeObject<RootObject>(responseFromServer);
To get the member names into a List<string>:
List<string> members = obj.members.data.Select(d => d.name).ToList();
Note: You need to have using System.Linq; at the top of your file in order to use the Select and ToList methods.
As far as displaying the data in a windows form app, there's not a "best" component-- it depends on what you're trying to accomplish as to what control you would choose to use. For example, if all you want to do is display the list of names in a multi-line textbox, you could do this:
textBox1.Text = string.Join("\r\n", members);
If you want to allow the user to be able to select individual names and do something based on that selection, you would probably want to use a ListBox or a ComboBox instead. You can populate a ListBox or ComboBox like this:
listBox1.DisplayMember = "name";
listBox1.DataSource = obj.members.data;
That should be enough to get you started.

Does Web Api support two and multi dimensional arrays for serialization and parameter binding?

I know that web services with Web Api can handle all the serialization and parameter (or data) binding tasks automatically for one dimensional arrays.
For example, a model class like the following one can be converted to JSON/XML and bound to a parameter of type Person automatically by the web api framework:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public double[] Notes { get; set; } // 1-dim array
}
What if the model class includes a two or multi dimensional array, like the following one? Can Web Api also handle such arrays automatically, or does the user need to write some extra code for serialization and data binding?
public class Person2
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public double[,] NoteMatrix { get; set; } // 2-dim array
}

EF Code First: Many-to-many and one-to-many

This is probably just because my knowledge with the EF Code First fluent API is lacking, but I'm stumped.
I want to model the following:
A Groups collection with Id and Name
A Users collection with Id and Name
Each user is assigned to exactly one primary group
Each user may have zero or many secondary groups
The table structure I'm going for would look like:
Groups
Id
Name
Users
Id
Name
PrimaryGroupId
SecondaryGroupAssignments
UserId
GroupId
I've been beating my head against a wall trying to model this with EF Code First, but I can't get it to accept both relationships between User and Group. Sorry for not posting any .NET code (I'm happy to), but it's probably all wrong anyway.
Is there a way to make EF model this? I'm assuming I have to do some sort of configuration with the Fluent API. Maybe a better question is: is there any good, definitive reference for the Fluent API?
Thanks!
Try this (untested):
public class Group
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> PrimaryUsers { get; set; }
public virtual ICollection<User> SecondaryUsers { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int PrimaryGroupId { get; set; }
public virtual Group PrimaryGroup { get; set; }
public virtual ICollection<Group> SecondaryGroups { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Group> Groups { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasRequired(u => u.PrimaryGroup)
.WithMany(g => g.PrimaryUsers)
.HasForeignKey(u => u.PrimaryGroupId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasMany(u => u.SecondaryGroups)
.WithMany(g => g.SecondaryUsers)
.Map(m => m.MapLeftKey("UserId")
.MapRightKey("GroupId")
.ToTable("SecondaryGroupAssignments"));
}
}
Based on Ladislav's excellent answer, here's how to do it without using any mappings - just attributes applied to the Model classes themselves:
public class Group
{
public int Id { get; set; }
[MaxLength(300)]
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
[MaxLength(300)]
public string Name { get; set; }
[ForeignKey("PrimaryGroup")]
public int PrimaryGroupId { get; set; }
[Required]
public Group PrimaryGroup { get; set; }
[InverseProperty("Users")]
public ICollection<Group> SecondaryGroups { get; set; }
}
Notes
If you want, you can add the virtual keyword to the 2 ICollections and the Group. This allows lazy-loading. Performance-wise, I don't recommend it, but it is possible.
I included MaxLength attributes with an arbitrary (but safe) length of 300, because putting strings out in EF without a MaxLength gets you low-performance NVarChar(MAX) columns. Totally irrelevant to what's being asked but better to post good code.
I recommend against class names "User" and "Group" for your EF classes. They're going to complicate any SQL you attempt to run later, having to type [User] and [Group] to access them, and complicate using these classes in MVC Controllers where your class User will conflict with the Context property User that gives you access to the Asp.Net Identity library.

RIA Services validation order

So I have some validations in my metadata like the following:
internal sealed class Metadata
{
[Key]
[ReadOnly(true)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string CountryCode { get; set; }
[CustomValidation(typeof(PCNValidator), "SetNumber")]
public string Number { get; set; }
}
I have some code to validate the Number property as you can see here, but I need the other Required properties of some of the attributes to fire first.
How can I achieve that?
You could make your PCNValidator return success until name and countryCode have been completed. Once that condition had been satisfied you could then do the remaining validation checks on Number. Not a wonderful solution but it does allow for your ordering requirement.
As far as I could find out, the answer to this question is NO, there's no way to tell an order in property-level validation.
Having said that, every Required property is validated before the others.
What I did in order to achive what I wanted was adding a type validator for the class. Type validators are always fired after property validators, which is exactly what I needed.
here's my code:
[MetadataType(typeof(PCN.Metadata))]
[CustomValidation(typeof(PCNValidator), "ValidateInsert")]
public partial class PCN : IValidate
{
internal sealed class Metadata
{
[Key]
[ReadOnly(true)]
public int Id { get; set; }
[Required(AllowEmptyStrings=false)]
public string Name { get; set; }
[Required]
public string CountryCode { get; set; }
}
}

Resources