How do I construct my RavenDb where clause for this document, given these requirements? - ravendb

This question builds on the following question (s)
Indexing : How do I construct my RavenDb static indexes for this document, given these requirements?
Simple Where clause with paging : How to construct a proper WHERE clause with RavenDb
The essence of the question is how do I dynamically add or remove fields to participate in a where clause?
Document:
[Serializable]
public class Product
{
public string AveWeight { get; set; }
public string BrandName { get; set; }
public string CasePack { get; set; }
public string Catalog { get; set; }
public decimal CatalogId { get; set; }
public decimal CategoryId { get; set; }
public string Info { get; set; }
public bool IsOfflineSupplierItem { get; set; }
public bool IsRebateItem { get; set; }
public bool IsSpecialOrderItem { get; set; }
public bool IsSpecialPriceItem { get; set; }
public bool IsTieredPricingItem { get; set; }
public string ItemNum { get; set; }
public string ManufactureName { get; set; }
public string ManufactureNum { get; set; }
public decimal OffineSupplierId { get; set; }
public string PackageRemarks { get; set; }
public decimal Price { get; set; }
public decimal PriceGroupId { get; set; }
public decimal ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public string SupplierName { get; set; }
public string UOM { get; set; }
public string Upc { get; set; }
public string Url { get; set; }
}
Index:
if (store.DatabaseCommands.GetIndex("Products_Index") == null)
{
store.DatabaseCommands.PutIndex("Products_Index", new IndexDefinitionBuilder<Product>
{
Map = products => from p in products
select new { p.CatalogId,
p.HasPicture,
p.INFO2,
p.IsOfflineSupplierItem,
p.IsRebateItem,
p.IsSpecialOrderItem,
p.IsSpecialPriceItem,
p.IsTieredPricingItem,
p.Price },
Indexes =
{
{ x => x.INFO2, FieldIndexing.Analyzed },
{ x => x.CatalogId, FieldIndexing.Default},
{ x => x.HasPicture, FieldIndexing.Default},
{ x => x.IsOfflineSupplierItem, FieldIndexing.Default},
{ x => x.IsRebateItem, FieldIndexing.Default},
{ x => x.IsSpecialOrderItem, FieldIndexing.Default},
{ x => x.IsSpecialPriceItem, FieldIndexing.Default},
{ x => x.IsTieredPricingItem, FieldIndexing.Default},
{ x => x.Price, FieldIndexing.Default}
}
});
}
Naive Where clause
string t1 = "foo";
bool t2 = true;
decimal t3 = 100m;
products = DocumentSession.Query<Product>()
.Statistics(out stats)
.Where(p => p.INFO2.StartsWith(t1) && p.IsRebateItem == t2 && p.CatalogId = t3)
.OrderByField(columnToSortBy, columnToSortByAsc)
.Skip(pageIndex * pageSize)
.Take(pageSize)
.ToList()
;
First Pass at Advanced Query
var products = s.Advanced.LuceneQuery<Product>("Products")
.WhereEquals("Catalog", "National Catalog")
.ToList()
;
which throws an exception
A first chance exception of type 'Lucene.Net.QueryParsers.QueryParser.LookaheadSuccess' occurred in Lucene.Net.dll
A first chance exception of type 'System.IO.IOException' occurred in Lucene.Net.dll
Second pass (works)
result = s.Advanced.LuceneQuery<Product>("Products_Index")
.Where("CatalogId:(736275001) AND HasPicture:(true) AND IsOfflineSupplierItem:(false)")
.ToArray();
Third Pass (and fastest yet)
result = s.Advanced.LuceneQuery<Product>("Products/Index")
.Statistics(out stats)
.WhereStartsWith("INFO2", "ink")
.AndAlso()
.WhereStartsWith("INFO2", "pen")
.AndAlso()
.WhereEquals("CatalogId", 736275001)
.AndAlso()
.WhereEquals("HasPicture", true)
.AndAlso()
.WhereEquals("IsOfflineSupplierItem", false)
.AndAlso()
.WhereEquals("IsRebateItem", false)
.AndAlso()
.WhereEquals("IsSpecialOrderItem", false)
.AndAlso()
.WhereEquals("IsSpecialPriceItem", false)
.ToArray()
;

If you want to do this dynamically, you can use the DocumentSession.Advanced.LuceneQuery, which allows you to pass strings as the property names for the index.
That way, you don't have to deal with the strongly typed issues.

Related

Dotnet core automapper orderItems

Now I am creating a website where you can place orders.
There we have Order, OrderItem and Item.
public class Order
{
public int Id { get; set; }
public User User { get; set; }
public int? UserId { get; set; }
public ICollection<OrderItem> OrderItems { get; set; }
public int TotalPrice { get; set; }
public string Status { get; set; }
public DateTime CreatedAt { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
public int ItemId { get; set; }
public virtual Item Item { get; set; }
public int Count { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public double TotalPrice { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
public int ItemId { get; set; }
public Item Item { get; set; }
public int Count { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public double TotalPrice { get; set; }
}
Upon creation of the order I will receive:
{
"orderItems": [
{
"itemId": 1,
"count": 4
}
]
}
and I have added in controller:
var userFromRepo = await _repo.GetUser (userId);
OrderForCreationDto.UserId = userId;
var order = _mapper.Map<Order> (OrderForCreationDto);
// userFromRepo.Orders.Add(order);
_repo.Add (order);
if (await _repo.SaveAll ())
{
var OrderToReturn = _mapper.Map<OrderForCreationDto> (order);
return Ok (OrderToReturn);
}
and in automapper:
CreateMap<Order, OrderForCreationDto> ();
CreateMap<OrderItemForCreationDto, OrderItem> ()
.ForMember (dest => dest.TotalPrice, opt => {
opt.MapFrom (d => d.Item);
opt.ResolveUsing (d => d.Item.Price * d.Count);
});
but always the mapping for OrderItem => item is null and so its giving error inside automapper.
I know its a long question but its killing me, I would appreciate if you could help. Thank you in advance
You are using older version of Automapper. In the version 8.0 ResolveUsing was consolidated with MapFrom.
Looks like you have source and destination switched. Try code below or adding .Reversemap()
CreateMap<OrderItem, OrderItemForCreationDto> ()
.ForMember (dest => dest.TotalPrice, opt =>
{
opt.MapFrom (d => d.Item);
opt.ResolveUsing (d => d.Item.Price * d.Count);
});

ASP.NET MVC query lambda expression

Hello I have problem in one query. Why it's always return no value.
public List<UserDetail> userSearchModel(UserSearchModel searchModel)
{
string userid = User.Identity.GetUserId();
var user = _dbContext.UserDetails.Where(x => x.Id == userid);
var result = _dbContext.UserDetails.Except(user).ToList().AsQueryable();
if (searchModel != null)
{
if (searchModel.LanguageId.Count() != 0)
{
List<UserDetailLanguage> usrDetails = new List<UserDetailLanguage>();
foreach (var item in searchModel.LanguageId)
{
var details = _dbContext.UserDetailLanguages.Where(x => x.LanguageId == item).ToList();
foreach (var item2 in details)
{
usrDetails.Add(item2);
}
}
result = result.Where(x => x.UserDetailLanguages == usrDetails);
}
}
return result.ToList();
}
I want to get results which are the same in usrDetails list and in result.UserDetailLanguages.
In result.UserDetailLanguages I have record equals to record in usrDetails but this not want retrieve.
Here is my model:
public class UserDetail
{
public UserDetail()
{
this.UserDetailLanguages = new HashSet<UserDetailLanguage>();
}
[Key, ForeignKey("User")]
public string Id { get; set; }
public DateTime Birthday { get; set; }
public string Sex { get; set; }
public string Country { get; set; }
public string About { get; set; }
[NotMapped]
public int Age { get { return DateTime.Now.Year - Birthday.Year; } }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<UserDetailLanguage> UserDetailLanguages { get; set; }
}
public class UserDetailLanguage
{
public Int32 Id { get; set; }
public virtual UserDetail UserDetail { get; set; }
public string UserDetailId { get; set; }
public virtual Language Language { get; set; }
public Int32 LanguageId { get; set; }
public Boolean IsKnown { get; set; }
public static implicit operator List<object>(UserDetailLanguage v)
{
throw new NotImplementedException();
}
}
public class Language
{
public Language()
{
this.UserDetailLanguages = new HashSet<UserDetailLanguage>();
}
public int Id { get; set; }
public string Value { get; set; }
public string Name { get; set; }
public virtual ICollection<UserDetailLanguage> UserDetailLanguages { get; set; }
}
What I'm doing wrong?
If you want to see if your value is in a list you use the Contains function of the list -- like this:
result = result.Where(x => usrDetails.Contains(x.UserDetailLanguage));
If you want to see if there are any items in both lists you can use intersection like this:
result = result.Where(x => usrDetails.Intersect(x.UserDetailLanguage).Count() > 0);
Looks like you are checking equality between lists in following code
result = result.Where(x => x.UserDetailLanguages == usrDetails);
This might not work, to check equality for lists you can use something like
Enumerable.SequenceEqual(FirstList.OrderBy(fList => fList),
SecondList.OrderBy(sList => sList))

Entity Framework Parent\Child Retrieval

I have an ID of a "Component" parent record that I need to retrieve all the "Attachment" child records. The grid I am using need fields returned an placed in "TheComponentAttachmentsJoinedTable" I am only able to retrieve one record. I have used the value of FirstorDefault. That is the only way it will accept the line of code without complaining about the IEnumerable to int. Could someone please explain what is incorrect?
public class Component
{
public int ID { get; set; }
public string ComponentCode { get; set; }
public string ComponentDescription { get; set; }
public double ComponentWeight { get; set; }
public double ComponentQuantity { get; set; }
public string LastModUser { get; set; }
public DateTime LastModDate { get; set; }
public virtual ICollection<Attachment> Attachments { get; set; }
public virtual ICollection<Product> Products { get; set; }
public virtual ICollection<Element> Elements { get; set; }
}
public class Attachment
{
public int ID { get; set; }
public string AttachmentDescription { get; set; }
public string OriginalName { get; set; }
public string MimeType { get; set; }
public byte[] bytes { get; set; }
public string LastModUser { get; set; }
public DateTime LastModDate { get; set; }
//Navigation
public virtual ICollection<Element> Elements { get; set; }
public virtual ICollection<Component> Components { get; set; } //lt M-m
}
public class TheComponentAttachmentsJoinedTable
{
public int ComponentID { get; set; }
public int AttachmentID { get; set; }
public string OriginalName { get; set; }
}
public static List<TheComponentAttachmentsJoinedTable> ComponentAttachments_GetAllByComponentID(int ComponentID)
{
using (TheContext TheDB = new TheContext())
{
var r = (from x in TheDB.Component
.Where(x => x.ID == ComponentID)
.Include(x => x.Attachments)
select new TheComponentAttachmentsJoinedTable
{
ComponentID = x.ID,
AttachmentID = x.Attachments.Select(y => (y.ID)).FirstOrDefault(),
OriginalName = x.Attachments.Select(y => y.OriginalName).FirstOrDefault().ToString(),
}
);
return r.ToList();
}

Losing data on .Where(expression) to list()

Func<View_Album_Search, bool> expressionAlbum = Al => Al.name.Contains(text) || Al.soundName.Contains(text) || Al.artist.Contains(text);
var query = view_Album_SearchRepository.Where(expressionAlbum);
var b = query.Count(); (*Count = 1440*)
(*Lose data *)
var a = query.ToList(); (*Count = 154*)
/***************************************************\
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate)
{
return _context.Set<TEntity>().Where(predicate);
}
MODEL
public partial class View_Album_Search
{
public string name { get; set; }
public decimal id_album { get; set; }
public string soundName { get; set; }
public string artist { get; set; }
public byte feature { get; set; }
public Nullable<System.DateTime> album_date { get; set; }
public Nullable<decimal> hits { get; set; }
public string artist_twitter { get; set; }
public Nullable<int> feature_order { get; set; }
public string video_url { get; set; }
}
I dont understand, if I do it on get all works fine.
Aditional information
On debug mode when he do .toList() he execute the exrpessionAlbum again
Func<View_Album_Search, bool> expressionAlbum = Al => Al.name.ToLower().Contains(text.ToLower()) || Al.artist.ToLower().Contains(text.ToLower());

Column Property AutoMapping

There is o possibility to create a convention for Column naming:
I have this piece of code:
public AutoPersistenceModel Generate()
{
var result = AutoPersistenceModel.MapEntitiesFromAssemblyOf<User>()
.Where(GetAutoMappingFilter)
.WithConvention(GetConventions);
return result;
}
private bool GetAutoMappingFilter(Type t)
{
return
t.GetInterfaces().Any(
x => x.IsGenericType && (x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>)));
}
private static void GetConventions(Conventions conventions)
{
conventions.GetPrimaryKeyNameFromType = type => type.Name.ToLower() + "_id";
conventions.FindIdentity = type => type.Name.ToLower() == "id";
conventions.GetTableName = type =>
{
if (!type.Name.Contains("Lookup"))
{
return Inflector.Net.Inflector.Pluralize(type.Name).ToLower();
}
return Inflector.Net.Inflector.Underscore(type.Name)
.Replace("lookup", "lu").ToLower();
};
conventions.IsBaseType = DontMapAsJoinedSubclassTypesInheritedFrom;
conventions.GetForeignKeyNameOfParent = type => Inflector.Net.Inflector.Underscore(type.Name) + "_id";
conventions.GetForeignKeyName = type => Inflector.Net.Inflector.Underscore(type.Name) + "_id";
conventions.OneToManyConvention = m => m.Cascade.All();
}
private static bool DontMapAsJoinedSubclassTypesInheritedFrom(Type arg)
{
var derivesFromEntity = arg == typeof(Entity);
var derivesFromEntityWithTypedId = arg.IsGenericType &&
(arg.GetGenericTypeDefinition() == typeof(EntityWithTypedId<>));
return derivesFromEntity || derivesFromEntityWithTypedId;
}
and an Entity class
public class Organisation : EntityWithTypedId<int>
{
public virtual Organisation Parent { get; set; }
public virtual LookOrganisationType OrganisationType { get; set; }
[DomainSignature]
public virtual string OrganisationName { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string Postcode { get; set; }
public virtual LookupCountry Country { get; set; }
public virtual string TelNo { get; set; }
public virtual string FaxNo { get; set; }
public virtual string Email { get; set; }
public virtual User Contact { get; set; }
public virtual DateTime? DateCreated { get; set; }
public virtual DateTime? DateAmended { get; set; }
public virtual bool Active { get; set; }
}
Finally I want to have a column for, let's say TelNo like tel_no.
So the Convention is if Property contains capital letter in the middle ti should be underscored. Inflector.Net.Inflector.Underscore works fine. But I do not know how to write the convention.
Somethig like:
(conventions.GetPropertyName = type => Inflector.Net.Inflector.Underscore(type.ColumnName))
Thanks