I'm trying to implement this faceted search logic: http://ravendb.net/docs/2.0/client-api/faceted-search. But the hits of every price range, that are returned from the database, do not work as expected; all the hits are grouped at the last price range.
My product document looks like this:
{
"Sku": "000000000000069673",
"Title": "APPLE ME186",
"Brand": "APPLE",
"RegularPrice": 84.99,
"ReferencePrice": 0.0,
"YouSavePrice": 0.0,
"ShortDescription": "",
"Description": "",
"CategoryHierarchyPath": "Beeld en geluid/Hoofdtelefoons/In-ear koptelefoon",
"Categories": [
"0/Beeld en geluid",
"1/Beeld en geluid/Hoofdtelefoons",
"2/Beeld en geluid/Hoofdtelefoons/In-ear koptelefoon"
],
"Stocks": [
{
"Quantity": ,
"Branch": ""
}
],
"Images": [],
"Attributes": [
{
"Name": "",
"Value": ""
}
]
}
The index I'm querying against:
public class CategoryProducts : AbstractIndexCreationTask<Product, CategoryProducts.ReduceResult>
{
public class ReduceResult
{
public string Category { get; set; }
public string Title { get; set; }
public decimal RegularPrice { get; set; }
public string ShortDescription { get; set; }
public int Description { get; set; }
}
public CategoryProducts()
{
Map = products =>
from p in products
from c in p.Categories
select new
{
Category = c,
Title = p.Title,
RegularPrice = p.RegularPrice,
ShortDescription = p.ShortDescription,
Description = p.Description
};
}
}
The FacetSetup:
Facets = new List<Facet>
{
new Facet
{
Name = "RegularPrice",
Mode = FacetMode.Ranges,
Ranges =
{
"[NULL TO Dx200.0]",
"[Dx200.0 TO Dx400.0]",
"[Dx400.0 TO Dx600.0]",
"[Dx600.0 TO Dx800.0]",
"[Dx800.0 TO NULL]",
}
}
}
The Query:
var priceRangeFacets = Session.Query<CategoryProducts.ReduceResult, CategoryProducts>()
.Where(r => r.Category.StartsWith("1/Beeld en geluid/Hoofdtelefoons")).ToFacets("facets/PriceRanges")
The result:
[0] = {Range: [NULL TO Dx200.0], Hits: 0}
[1] = {Range: [Dx200.0 TO Dx400.0], Hits: 0}
[2] = {Range: [Dx400.0 TO Dx600.0], Hits: 0}
[3] = {Range: [Dx600.0 TO Dx800.0], Hits: 0}
[4] = {Range: [Dx800.0 TO NULL], Hits: 77}
Note that I have products in the database that are cheaper than 800.
P.S. I'm using RavenDB-Build-2330
Resolved after Ayende's correction for the failing test I had created:
When doing range searches on a numeric field, you need to use the _Range postfix
You need to do [NULL TO Dx200.0}
[ Is inclusive, } is exclusive.
So our facet setup should be declared like:
Facets = new List<Facet>
{
new Facet
{
Name = "RegularPrice_Range",
Mode = FacetMode.Ranges,
Ranges =
{
"[NULL TO Dx200.0}",
"[Dx200.0 TO Dx400.0}",
"[Dx400.0 TO Dx600.0}",
"[Dx600.0 TO Dx800.0}",
"[Dx800.0 TO NULL}",
}
}
}
Related
I have an entity like:
public class TEvent
{
public int? January { get; set; }
public int? February { get; set; }
public int? March { get; set; }
public int? April { get; set; }
public int? May { get; set; }
public int? June { get; set; }
public int? July { get; set; }
public int? August { get; set; }
public int? September { get; set; }
public int? October { get; set; }
public int? November { get; set; }
public int? December { get; set; }
//and much more
}
What I want my LINQ code to achieve:
SELECT MonthCode, * FROM T_Events
CROSS APPLY (VALUES (1, January), (2, February), (3, March), (4, April), (5, May), (6, June), (7, July), (8, August), (9, September), (10, October), (11, November), (12, December)) AS CA(MonthCode, Display)
WHERE Display = -1
The problem is that I don't know how to have LINQ know it is a column name.
What I've tried
var dd = new List<object>()
{
new {January = 1 },
new {February = 2},
new {March = 3},
new {April = 4},
new { May = 5},
new {June = 6},
new {July = 7},
new {Augest = 8},
new {September = 9},
new {October = 10},
new {November = 11},
new {December = 12}
};
var q =
from events in _context.TEvents
from mds in dd
Now when I write mds. I don't get anything because of course it is of type object, but if I don't use object how would I specify custom column names and get the value of 'Display'
Expected result:
The value of Months(Jan, feb etc...) can be (0 or -1). When the Columns are converted to Rows, I get 12 rows, each with it's own MonthCode and display, now let's say for a record March and April are -1, then the 3rd and 4th record will have Display = -1 and the rest will have 0, while all will retain it's month codes
I would suggest to use linq2db.EntityFrameworkCore, note that I'm one of the creators.
This extension brings power of linq2db to EF Core projects. And library supports join to local collections.
class MonthDescription
{
public int MonthCode { get; set; }
public string Display { get; set; }
}
var months = new []
{
new MonthDescription { MonthCode = 1, Display = "January" },
new MonthDescription { MonthCode = 2, Display = "February" },
new MonthDescription { MonthCode = 3, Display = "March" },
new MonthDescription { MonthCode = 4, Display = "April" },
new MonthDescription { MonthCode = 5, Display = "May" },
new MonthDescription { MonthCode = 6, Display = "June" },
new MonthDescription { MonthCode = 7, Display = "July" },
new MonthDescription { MonthCode = 8, Display = "Augest" },
new MonthDescription { MonthCode = 9, Display = "September" },
new MonthDescription { MonthCode = 10, Display = "October" },
new MonthDescription { MonthCode = 11, Display = "November" },
new MonthDescription { MonthCode = 12, Display = "December" }
};
var query =
from event in _context.TEvents.ToLinqToDB() // switching LINQ provider
from md in months
select new
{
event,
md
};
Thanks #Svyatoslav Danyliv For your answer. I've also found another way to achieve what I want through Union.
First Write the main query:
var evAll = from child in _context.TEvents
join parent in _context.TEventDomains
on child.ID equals parent.ID
join p in _context.TPriorities
on parent.IDPriority equals p.Idpriority into PJoin
from p in PJoin.DefaultIfEmpty()
select new TEventExtended(child, p.PriorityCode)
Now I can select for each month and union the answer. like
from ev in evAll
select new TEventExtended(ev, 1, ev.January))
.Union(
from ev in evAll
select new TEventExtended(ev, 2, ev.February))
...etc etc
Here, I created a class/record which extend TEvent by 3 properties i.e. MonthCode, Display, Priority, and created constructors which copies data from the original TEvent/TEventExtended
NOTE: If you're using C# 10. You don't need to create constructors, simply use: new TEventExtended() with { MonthCode = 12, Display = ev.December}
Finally after adding 12 unions
.Union(
from ev in evAll
select new TEventExtended(ev, 12, ev.December))
.Where(x => x.Display == -1)
.OrderBy(x => x.MonthCode >= request.Month ? x.MonthCode : x.MonthCode + 12)
.ThenBy(x => x.PCode)
.Select(x =>
new MyFinalDTO
{
//projection
}).ToListAsync(cancellationToken);
Im using code first approach in my project. Im trying to create dynamic Create action and dynamic Complete(UnitOfWork) action as well. Im getting that error after my function adding first value.
Let me show you to my function :
public void WebFairHallSeatingCreator(int webFairHallID)
{
int[] hallSeatingOrderColumnValue = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
string[] hallSeatingOrderRowValue = { "a", "b", "c", "d", "e", "f", "g" };
var hallSeatingOrder = new HallSeatingOrder();
for (int row = 0; row < hallSeatingOrderRowValue.Length; row++)
{
for (int col = 1; col <= hallSeatingOrderColumnValue.Length; col++)
{
if ((hallSeatingOrderRowValue.GetValue(row).ToString() == "c") || (hallSeatingOrderRowValue.GetValue(row).ToString() == "d"))
{
if ((col == 5) || (col == 6) || (col == 7))
{
hallSeatingOrder.HallSeatingOrderRowValue = "x";
hallSeatingOrder.HallSeatingOrderColumnValue = 15;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
}
else
{
hallSeatingOrder.HallSeatingOrderRowValue= hallSeatingOrderRowValue.GetValue(row).ToString();
hallSeatingOrder.HallSeatingOrderColumnValue = col;
hallSeatingOrder.WebFairHallID = webFairHallID;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
_unitOfWorkWFH.Complete();// This is the point
}
}
else
{
hallSeatingOrder.HallSeatingOrderRowValue = hallSeatingOrderRowValue.GetValue(row).ToString();
hallSeatingOrder.HallSeatingOrderColumnValue = col;
hallSeatingOrder.WebFairHallID = webFairHallID;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
_unitOfWorkWFH.Complete();// This is the point
}
}
}
}
here its my HallSeatingOrder class :
public class HallSeatingOrder : Base
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int HallSeatingOrderID { get; set; }
[Required]
public int WebFairHallID { get; set; }
public int? CompanyID { get; set; }
[Required]
public int HallSeatingOrderColumnValue { get; set; }
[Required]
public string HallSeatingOrderRowValue { get; set; }
public bool HallSeatingOrderIsSpecial { get; set; }
public Company Company { get; set; }
public WebFairHall WebFairHall { get; set; }
}
public class HallSeatingOrderConfiguration : IEntityTypeConfiguration<HallSeatingOrder>
{
public void Configure(EntityTypeBuilder<HallSeatingOrder> builder)
{
builder.HasKey(x => x.HallSeatingOrderID);
builder.HasOne(x => x.Company)
.WithMany(x => x.HallSeatingOrders)
.HasForeignKey(x => x.CompanyID)
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.WebFairHall)
.WithMany(x => x.HallSeatingOrders)
.HasForeignKey(x => x.WebFairHallID)
.OnDelete(DeleteBehavior.NoAction);
}
}
i allready look out of every question with my problem.
i try using ValueGeneratedOnAdd() and [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] but none of it worked on me.
thanks for the #IvanStoev, i solve that problem. there is nothing wrong with my model and my configuration. there was a one mistake and let me show u that:
public void WebFairHallSeatingCreator(int webFairHallID)
{
int[] hallSeatingOrderColumnValue = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
string[] hallSeatingOrderRowValue = { "a", "b", "c", "d", "e", "f", "g" };
for (int row = 0; row < hallSeatingOrderRowValue.Length; row++)
{
for (int col = 1; col <= hallSeatingOrderColumnValue.Length; col++)
{
if ((hallSeatingOrderRowValue.GetValue(row).ToString() == "c") || (hallSeatingOrderRowValue.GetValue(row).ToString() == "d"))
{
if ((col == 5) || (col == 6) || (col == 7))
{
var hallSeatingOrder = new HallSeatingOrder();
hallSeatingOrder.HallSeatingOrderRowValue = "x";
hallSeatingOrder.HallSeatingOrderColumnValue = 15;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
_unitOfWorkWFH.Complete();
}
else
{
var hallSeatingOrder = new HallSeatingOrder();
hallSeatingOrder.HallSeatingOrderRowValue= hallSeatingOrderRowValue.GetValue(row).ToString();
hallSeatingOrder.HallSeatingOrderColumnValue = col;
hallSeatingOrder.WebFairHallID = webFairHallID;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
_unitOfWorkWFH.Complete();
}
}
else
{
var hallSeatingOrder = new HallSeatingOrder();
hallSeatingOrder.HallSeatingOrderRowValue = hallSeatingOrderRowValue.GetValue(row).ToString();
hallSeatingOrder.HallSeatingOrderColumnValue = col;
hallSeatingOrder.WebFairHallID = webFairHallID;
_unitOfWorkWFH.RepositoryHallSeatingOrder.Create(hallSeatingOrder);
_unitOfWorkWFH.Complete();
}
}
}
}
i need to create that var hallSeatingOrder = new HallSeatingOrder(); for each of for loop,thats all. Thanks to him.
I have the following code:
public class WorkOrderByUserId : AbstractMultiMapIndexCreationTask<WorkOrderByUserId.Result>
{
public WorkOrderByUserId()
{
this.AddMap<WorkOrder>(items
=> from item in items
select new Result
{
OwnerId = item.OwnerId,
WorkOrder = new WorkOrderLookupDto
{
Id = item.Id,
Name = item.EventName
},
WorkOrders = null
});
this.AddMap<Invoice>(items
=> from item in items
select new Result
{
OwnerId = item.WorkOrder.OwnerId,
WorkOrder = new WorkOrderLookupDto
{
Id = item.WorkOrder.Id,
Name = item.WorkOrder.EventName
},
WorkOrders = null
});
this.Reduce = results => from result in results
group result by result.OwnerId
into g
select new Result
{
OwnerId = g.Key,
WorkOrders = g.Select(x => x.WorkOrder),
WorkOrder = null
};
this.Indexes.Add(x => x.OwnerId, FieldIndexing.Default);
}
public class Result
{
public string OwnerId { get; set; }
public IEnumerable<WorkOrderLookupDto> WorkOrders { get; set; }
public WorkOrderLookupDto WorkOrder { get; set; }
}
}
It gets me very close to where I want to be, however I seem to be missing something and I'm losing information and I'm not sure why.
Using the Map/Reduce Visualizer I notice the MAP is displaying the Results (i.e. WorkOrders is populated, and WorkOrder is null)
As this point I was expecting to have a bunch of items with NULL WorkOrders and a valid WorkOrder, which I expected to reduce down into the WorkOrders collection.
When I look at the final reduce in the visualizer, I notice my WorkOrder is NULL and my WorkOrders are missing entirely.
And when I look at the FINAL result of the Index I see what I'm looking for, just without the actual data I'm looking for.
What do I need to change to get my final WorkOrders to NOT be NULL?
I was able to get my desired result using the following code:
public class WorkOrderByUserId : AbstractMultiMapIndexCreationTask<WorkOrderByUserId.Result>
{
public WorkOrderByUserId()
{
this.AddMap<WorkOrder>(items
=> from item in items
select new Result
{
OwnerId = item.OwnerId,
WorkOrders = new[]
{
new WorkOrderLookupDto
{
Id = item.Id,
Name = item.EventName
}
}
});
this.AddMap<Invoice>(items
=> from item in items
select new Result
{
OwnerId = item.WorkOrder.OwnerId,
WorkOrders = new[]
{
new WorkOrderLookupDto
{
Id = item.WorkOrder.Id,
Name = item.WorkOrder.EventName
}
}
});
this.Reduce = results => from result in results
group result by result.OwnerId
into g
select new Result
{
OwnerId = g.Key,
WorkOrders = g.SelectMany(x => x.WorkOrders)
};
this.Indexes.Add(x => x.OwnerId, FieldIndexing.Default);
}
public class Result
{
public string OwnerId { get; set; }
public IEnumerable<WorkOrderLookupDto> WorkOrders { get; set; }
}
}
I would like to know the best way to compare 2 complex objects to know if they are equal by value, ie, their properties are the same? I tried the serialize method and not sure why they are not equal by value
Dim stream As New MemoryStream()
Dim bstream As New MemoryStream()
Dim clientOne As Jewellery.ClientInfo = New Jewellery.ClientInfo(New Jewellery.Company("a", "", "", "b", "", "e"), New Jewellery.Customer("a", "b", "c", "d", "", "", "", "f"))
Dim clientTwo As Jewellery.ClientInfo = New Jewellery.ClientInfo(New Jewellery.Company("a", "", "", "b", "", "e"), New Jewellery.Customer("a", "b", "c", "d", "", "", "", "f"))
formatter.Serialize(stream, clientOne)
formatter.Serialize(bstream, clientTwo)
Dim streamOneBytes As Byte() = stream.ToArray()
Dim streamTwoBytes As Byte() = bstream.ToArray()
Dim streamToCompareBytes As Byte() = streamToCompare.ToArray()
Dim i As Int16 = 0
Dim flag As Boolean
If streamOneBytes.Length <> streamTwoBytes.Length Then
MsgBox("False")
flag = False
Else
While i < streamOneBytes.Count
If streamOneBytes(i) <> streamTwoBytes(i) Then
flag = "False"
Else : flag = "True"
End If
i = i + 1
End While
End If
As you see in the above code, when I initialize 2 objects of the same type and compare, it works correctly. But when I add one object to say a List and then retrieve and compare to an object of similar type, it fails saying the binary width are different for both. Any advice? Thanks
public class IntegerPropertyEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return x.IntegerProperty == y.IntegerProperty;
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public class StringPropertyEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return x.StringProperty == y.StringProperty;
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public class AllPropertiesEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return ( x.IntegerProperty == y.IntegerProperty ) && ( x.StringProperty == y.StringProperty );
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public abstract class Main
{
public int IntegerProperty { get; set; }
public string StringProperty { get; set; }
public bool Equals( IEqualityComparer<Main> comparer, Main other )
{
return comparer.Equals( this, other );
}
}
public class ConcreteA : Main
{ }
public class ConcreteB : Main
{ }
class TemporaryTest
{
public static void Run()
{
var a = new ConcreteA();
a.IntegerProperty = 1;
a.StringProperty = "some";
var b = new ConcreteB();
b.IntegerProperty = 1;
a.StringProperty = "other";
Console.WriteLine( a.Equals( new IntegerPropertyEqualityCompare(), b ) );
Console.WriteLine( a.Equals( new StringPropertyEqualityCompare(), b ) );
Console.WriteLine( a.Equals( new AllPropertiesEqualityCompare(), b ) );
}
}
Maybe then somthing like this?
I'm not sure that I understand what you want to do.
So I go with IComparable<T>.
What is the best way for mapping collection of objects in NHibernate?
Now I am using bags, but maybe another approach can be more efficient?
Before wore Bag and ClassMapping, something very similar to this:
Bag(am => am.AlumnoMateriaId, map =>
{
map.Table("Calificacion");
map.Cascade(Cascade.None);
map.Key(k =>
{
k.Column("AlumnoId");
k.ForeignKey("FK_Calificacion_AlumnoMateria");
});
}, rel => rel.ManyToMany(p => p.Column("AlumnoId")));
Now Use the NHibernate.Mapping.Attributes, and a class would look like:
using NHMA = NHibernate.Mapping.Attributes;
[NHMA.Class(Table = " Calificacion ")]
public class Calificacion
{
[NHMA.Id(0, Name = "id", TypeType = typeof(Int32), Column = "Id", Access = "field")]
[NHMA.Generator(1, Class = "native")]
public Int32 id;
public virtual Int32 Id
{
get { return id; }
set { id = value; }
}
[NHMA.ManyToOne(2, Name = "calificacion", Access = "field", Column = "CalificacionID",
Class = "Calificacion", ClassType = typeof(Calificacion),
ForeignKey = "FK_Calificacion_Alumno", NotNull = false)]
private Calificacion calificaion;
public virtual Calificacion Calificaion
{
get { return calificaion; }
set { calificaion = value; }
}
[NHMA.Property(Name = "nombre", Access = "field", Column = "Nombre", Length = 50)]
private string nombre;
public virtual string Nombre
{
get { return nombre; }
set { nombre = value; }
}
}