how to write string array index in ravendb - c#

i have ravendb document called Orders like this
{
"MyOrders": [
"S1",
"S2"
],
"Id": "6666"
}
I will query this document and pass order string for example S1
Then it should return me that document as S1 matches it. I am pretty new to this ravendb. I am unable to find way. I have written only this so far
public class MyOrderIndexes: AbstractIndexCreationTask<Order>
{
public MyOrderIndexes()
{
Map = Orders => from Order in Orders
select new
{
ID= Order.Id
};
Index(x => x.Id, FieldIndexing.NotAnalyzed);
}
}
can someone help me

To query that, you don't need to create an index. Just do a query, Raven will create it for you.
This query should work just fine:
var hasS2 = session.Query<Orders>()
.Where(o => o.MyOrders.Contains("S2"))
.ToList();

One problem is the FieldIndexing on Id, and also that you need to map MyOrders to perform query on it.
Index:
public class MyOrderIndexes: AbstractIndexCreationTask<Order>
{
public MyOrderIndexes()
{
Map = Orders => from Order in Orders
select new
{
Id = Order.Id,
MyOrders = Order.MyOrders
};
}
}
Query:
var results = session
.Query<Order, MyOrderIndexes>()
.Where(x => x.MyOrders.Any(l => l == "S1"))
.ToList();
Model:
public class Order
{
public string Id { get; set; }
public ICollection<string> MyOrders { get; set; }
}

Related

LINQ to Entities, Where Any In

How to write 'Where Any In' in LINQ to Entity?
Here is my model :
class Chair
{
public int Id { get; set; }
public int TableId { get; set; }
public Table Table { get; set; }
}
class Table
{
public int Id { get; set; }
public ICollection<Chair> Chairs { get; set; }
public ICollection<Category> Categories { get; set; }
public Table()
{
Chairs = new List<Chair>();
Categories = new List<Category>();
}
}
class Category
{
public int Id { get; set; }
public ICollection<Table> Tables { get; set; }
}
I also got a simple list of Category :
List<Category> myCategories = new List<Category>(c,d,e);
I want to get only that Chairs that belongs to Table that got one of the Category from myCategories List. Thats what im trying to do :
var result =
ctx.Chairs.Where(x => x.Table.Categories.Any(y => myCategories.Any(z => z.Id == y.Id))).ToList();
I think its ok but what i get is error :
"Unable to create a constant value of type 'ConsoleApplication1.Category'. Only primitive types or enumeration types are supported in this context"
Try to compare with in-memory categories Ids collection, instead of categories collection.
var myCategoriesIds = myCategories.Select(c => c.Id).ToArray();
var result =
context.Chairs
.Where(
x => x.Table.Categories.Any(
y => myCategoriesIds.Contains(y.Id)))
.ToList();
this is because ctx.Chairs is a collection that is in database, you should retrieve that collection first in order to compare it with in-memory data:
var result = ctx
.Chairs
.AsEnumerable() // retrieve data
.Where(x =>
x.Table.Categories.Any(y =>
myCategories.Any(z => z.Id == y.Id)))
.ToList();
EDIT: that wouldn't be the correct thing to do if you have a lot of entities on database, what you can do is to split it into two queries:
var tables = ctx.Tables
.Where(x =>
x.Categories.Any(y =>
myCategories.Any(z => z.Id == y.Id)));
var result = ctx.Chairs
.Where(x =>
tables.Any(t=> t.Id == x.TableId))
.ToList();
You can select Ids from myCategories and use it last statement.
var CategoryIds = myCategories.Select(ct => ct.Id);
var result = ctx.Chairs.Where(x => x.Table.Categories.Any(y => CategoryIds.Any(z => z == y.Id))).ToList();

AutoMapper flatten nested collections

I try to figure out how to flatten a collection of Merchants, each containing a collection of Orders to a flat List of OrderViewModels.
Here my DTO:
public class Merchant
{
public string MerchantName { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public string OrderId { get; set; }
}
And Here's the view model:
public class OrderViewModel
{
public string MerchantName { get; set; }
public string OrderId { get; set; }
}
My Goal is to flatten a List<Merchant> to a List<OrderViewModel> whereas the following test structure should result in 6 view models:
var myMerchants = new List<Merchant>
{
new Merchant
{
MerchantName = "Merchant X",
Orders = new List<Order>
{
new Order { OrderId = "Order 1"},
new Order { OrderId = "Order 2"},
new Order { OrderId = "Order 3"}
}
},
new Merchant
{
MerchantName = "Merchant Y",
Orders = new List<Order>
{
new Order { OrderId = "Order 4"},
new Order { OrderId = "Order 5"},
new Order { OrderId = "Order 6"}
}
}
};
var models = Mapper.Map<List<OrderViewModel>>(myMerchants);
Because the cardinality of the root objects isn't 1:1, (i.e. 2 root Merchants need to map to 6 OrderViewModels), you may need to resort to a custom TypeConverter and operate at the collection level, where you can use .SelectMany to do the flattening:
public class MyTypeConverter : ITypeConverter<IEnumerable<Merchant>, List<OrderViewModel>>
{
public List<OrderViewModel> Convert(ResolutionContext context)
{
if (context == null || context.IsSourceValueNull)
return null;
var source = context.SourceValue as IEnumerable<Merchant>;
return source
.SelectMany(s => s.Orders
.Select(o => new OrderViewModel
{
MerchantName = s.MerchantName,
OrderId = o.OrderId
}))
.ToList();
}
}
Which you can then bootstrap:
Mapper.CreateMap<IEnumerable<Merchant>, List<OrderViewModel>>()
.ConvertUsing<MyTypeConverter>();
And then mapped as such:
var models = Mapper.Map<List<OrderViewModel>>(myMerchants);
An interesting finding is that, only do the below is enough to achieve the goal without automapper.
var models = myMerchants.SelectMany(s => s.Orders.Select(o => new OrderViewModel { MerchantName = s.MerchantName, OrderId = o.OrderId })).ToList();
Old question but thought would be helpful for newer versions.
I am using .Net core 2 with automapper. I prefer to do the ProjectTo extension of queryable
queryable
.SelectMany(outterClass => outterClass.innerList)
.AsQueryable()
.ProjectTo<OutterClassDto>();
Then, configure like so:
config.CreateMap<OuterClass, OuterClassDto>();
It's also possible to combine SelectMany with AutoMapper and do the mapping for each item in the flattened collection. You need two mappings for this Merchant -> OrderViewModel and Order -> OrderViewModel
var models = myMerchants.SelectMany(s => s.Orders.Select(o =>
{
var mappedItem = Mapper.Map<OrderViewModel>(s);
Mapper.Map(o, mappedItem);
return mappedItem;
})).ToList();

LINQ Sum list of items grouped by type inside list

I have the following order object which contains a list of order addons. I am trying to create a report that shows all the addon types and their quantities summed.
public class Order {
public IList<OrderAddon> OrderAddons { get; set; }
}
public class OrderAddon {
public enum OrderType { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
}
This is where I am at and can't figure out if the entire query is wrong of I am just missing something.
var query = from order in Model.Orders
from addon in order.OrderAddons
group order by addon.AddonType
into orderAddons select new
{
Name = orderAddons.Key,
Quantity = orderAddons.Sum(x => x.) << This is where I am stuck
};
When I hit . my intellisense is showing me properties in order object not the addon object.
That's because you're saying group order by ..., so the orderAddons object becomes a grouping of orders. You can use this if you're going to need properties from both objects:
from order in Model.Orders
from addon in order.OrderAddons
group new{addon, order} by addon.AddonType
into orderAddons select new
{
Name = orderAddons.Key,
Quantity = orderAddons.Sum(x => x.addon.Quantity)
};
If this is all the data you need, this is a little simpler:
from order in Model.Orders
from addon in order.OrderAddons
group order.Quantity by addon.AddonType
into quantityByAddonType select new
{
Name = quantityByAddonType.Key,
Quantity = quantityByAddonType.Sum()
};
an alternative syntax same result...
var result = Model.Orders
.SelectMany(order => order.OrderAddons)
.GroupBy(addon => addon.OrderType)
.Select(grouping => new
{
Name = grouping.Key,
Quantity = grouping.Sum(addon => addon.Quantity)
});

Getting List of Model1 with List of Model2 in it LINQ - MVC 4 EntityFramework 5

I have a requirement where I need to get a List of Model1 (List) using Linq, the Model1 have List of Model2 (List) in it and I need to fetch that also. For this I have created a Linq but m getting following error:
LINQ to Entities does not recognize the method
'System.Collections.Generic.List1 [OurCourse]
ToList[OurCourse](System.Collections.Generic.IEnumerable1
[OurCourse])' method, and this method cannot be translated into a
store expression.
Please refer below for detail:
I have two tables Colleges and Courses, with following columns:
College: ID, Name, Contact, City, Address
Cource: ID, CollegeID, Name, Years
My project have two view models for them, as follows:
public class OurCollege
{
public string Name { get; set; }
public string Contact { get; set; }
public List<OurCourse> MyCourses { get; set; }
}
public class OurCourse
{
public string Name { get; set; }
public int NumberOfYears { get; set; }
}
Here the the query query which I have prepared but I am getting the error:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = cld.Course
.Select(crs => new OurCourse()
{
Name = crs.Name,
NumberOfYears = crs.Years
}).ToList()
}).ToList();
How about doing like this:
MyCourses = from crs in cld.Course
select new OurCourse
{
Name = crs.Name,
NumberOfYears = crs.Years
}
Your complete query will look now:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = (from crs in cld.Course
select new OurCourse
{
Name = crs.Name,
NumberOfYears = crs.Years
}).ToList()
}).ToList();
Actually LINQ to Entities converts your query into SQL.It doesn't know how to translate ToList() in SQL
An alternate is to change you List<T> to IEnumerable<T> and remove ToList() frim your original code:
public IEnumerable<OurCourse> MyCourses { get; set; }
and in query:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = cld.Course
.Select(crs => new OurCourse()
{
Name = crs.Name,
NumberOfYears = crs.Years
})
}).ToList();
For more details visit this Entity Framework ToList() in nested type (LINQ to Entities does not recognize the method)
A foreach loop will work, you can write the query something like this
var colleges = db.Colleges
.Select(x => new OurCollege()
{
CollegeId = x.CollegeId,
Name = x.Name,
Contact = x.Contact
}).ToList();
foreach (var college in colleges)
{
college.MyCourse = db.Course.Where(x => x.CollegeId == college.CollegeId)
.Select(x => new OurCourse()
{
Name = x.Name,
NumberOfYears = x.Years
}).ToList()
}

C# LINQ sub-where

I have object
public class OrderItem
{
public string idProduct { get; set; }
public int quantity { get; set; }
public List<WarehouseItem> WarehouseInfo = new List<WarehouseItem>();
}
public class WarehouseItem
{
public string Name{ get; set; }
public string LocnCode{ get; set; }
}
and i need select items which have WarehouseInfo.LocnCode == "A1"
It is doesnt work when I use something like
var items = itemList.Where(x => x.WarehouseInfo.Where(y => y.LocnCode.Equals("A1")));
Your requirements could be interpreted one of three ways, so here's three solutions:
Give me all OrderItems where ANY WarehouseItem has a LocnCode of "A1":
var items = itemList.Where(i => i.WarehouseInfo.Any(w => w.LocnCode == "A1"));
Give me all WarehouseItems within the OrderItems that have a LocnCode of "A1":
var items = itemList.SelectMany(i => i.WarehouseInfo)
.Where(w => w.LocnCode.Equals("A1"));
Give me all OrderItems where ANY WarehouseItem has a LocnCode of "A1", and filter WarehouseInfo to only those WarehouseItems:
This can't be done in a simple Linq query because there's no way to change the contents of the existing objects. You're going to have to create new objects with the filtered values:
var items = itemList.Where(i => i.WarehouseInfo.Any(w => w.LocnCode == "A1"))
.Select(i => new OrderItem
{
idProduct = i.idProduct,
quantity = i.quantity,
WarehouseInfo = i.WarehouseInfo.Where(w => w.LocnCode.Equals("A1"));
.ToList()
}
);
Try
var items = itemList.Where(x => x.WarehouseInfo.Any(y => y.LocnCode.Equals("A1")));
The Where takes a predicate that should return a bool. Any will return true if at least one item in the collection returns true for the given predicate.

Categories