c# Linq, how return query with ENUM - linq

So from Front-end I get a string "test1,test2,test3" or "test1,test2" etc. (I can change this on number, it is not a problem);
In back-end I have this:
class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Color Color { get; set; }
}
public enum Color
{
Red = 1,
Blue = 2,
Pink = 3,
Orange = 4,
}
public async Task<Car> GetAllCars(string searchString)
{
switch (searchString)
{
case "How create here query guestion whcih inlude ENUMS":
query = query.Where( inlude x=> a.Color == x.Contains(x.Color))
break;
default:
query = query.Where(at =>
at.Id.ToString().Contains(searchString)
||
at.Name.Contains(searchString));
break;
}
}
I want return all query which have the same enums

If you want to return all cars, then you need to change the return type to List and then lets assume that you have some list of cars (List<Car>) and we should pick cars from there by name and color:
public async Task<List<Car>> GetAllCars(string searchString)
{
return cars.Where(x=>x.Name.Contains(searchString) || x.Color.ToString().Contains(searchString).ToList();
}

Related

Increment a value when conditions are met, otherwise set to zero

Given a list of strings, I'd like to create a list of the following object
class LineInfo
{
public string line { get; set; }
public bool isSearchMatch { get; set; }
public int searchMatchNumber { get; set; }
}
Where I'd like searchMatchNumber to have 1 for the 1st match, 2 for the 2nd, etc. Otherwise it can be zero
I set this up like so
IEnumerable<string> allLines; //pulled in from somewhere
IEnumerable<LineInfo> logInfoLines = allLines.Select((l, i) => new LineInfo
{
line = l,
isSearchMatch = l.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0
});
How can I set searchMatchNumber?
LINQ queries should not cause side effects like this. If you'd add an OrderBy you'd get a different result. I wouldn't use LINQ for this, you could provide a method:
class LineInfo
{
public string line { get; set; }
public bool isSearchMatch { get; set; }
public int searchMatchNumber { get; set; }
public static IEnumerable<LineInfo> GetSearchResult(IEnumerable<string> allLines, string search)
{
int matchCounter = 0;
var lineInfoList = new List<LineInfo>();
foreach (string line in allLines)
{
bool isMatch = line.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;
var li = new LineInfo
{
line = line,
isSearchMatch = isMatch,
searchMatchNumber = isMatch ? ++matchCounter : -1 // or whatever
};
lineInfoList.Add(li);
}
return lineInfoList;
}
}

Dynamic LINQ: Comparing Nested Data With Parent Property

I've a class with following structure:
public class BestWayContext
{
public Preference Preference { get; set; }
public DateTime DueDate { get; set; }
public List<ServiceRate> ServiceRate { get; set; }
}
public class ServiceRate
{
public int Id { get; set; }
public string Carrier { get; set; }
public string Service { get; set; }
public decimal Rate { get; set; }
public DateTime DeliveryDate { get; set; }
}
and I've dynamic linq expression string
"Preference != null && ServiceRate.Any(Carrier == Preference.Carrier)"
and I want to convert above string in Dynamic LINQ as follows:
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, null).Compile();
But it showing following error:
Please correct me what am I doing wrong?
It looks like you wanted to do something like this:
var bwc = new BestWayContext
{
Preference = new Preference { Carrier = "test" },
DueDate = DateTime.Now,
ServiceRate = new List<ServiceRate>
{
new ServiceRate
{
Carrier = "test",
DeliveryDate = DateTime.Now,
Id = 2,
Rate = 100,
Service = "testService"
}
}
};
string condition = "Preference != null && ServiceRate.Any(Carrier == #0)";
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, bwc.Preference.Carrier).Compile();
bool res = expression(bwc); // true
bwc.ServiceRate.First().Carrier = "test1"; // just for testing this -> there is only one so I've used first
res = expression(bwc); // false
You want to use Preference which belong to BestWayContext but you didn't tell the compiler about that. If i write your expression on Linq i will do as follows:
[List of BestWayContext].Where(f => f.Preference != null && f.ServiceRate.Where(g => g.Carrier == f.Preference.Carrier)
);
As you see i specified to use Preference of BestWayContext.

The Type of one of the Expression in the join clause is incorrect.Type inference failed in the call to join

Getting this error in GetDiseaseBySymptoms method below when trying to join two list of type DiseaseSymptomMapping & Symptom. Can anyhelp with better understanding suggest what went wrong with the code of GetDiseaseBySymptoms.
Note: Don't worry about the return type of GetDiseaseBySymptoms method, that will be taken care later once this issue is resolved.
class Program
{
static void Main(string[] args)
{
Disease malaria = new Disease { ID = 1, Name = "Malaria" };
Disease Cholera = new Disease { ID = 1, Name = "Cholera" };
Symptom Fever = new Symptom { ID = 1, Name = "Fever" };
Symptom Cough = new Symptom { ID = 2, Name = "Cough" };
Symptom Shevering = new Symptom { ID = 3, Name = "Shevering" };
List<DiseaseSymptomMapping> DiseaseDetails = new List<DiseaseSymptomMapping> {
new DiseaseSymptomMapping{ ID=1,disease=malaria,symptom=Fever},
new DiseaseSymptomMapping{ ID=2,disease=malaria,symptom=Shevering},
new DiseaseSymptomMapping{ ID=3,disease=Cholera,symptom=Fever},
new DiseaseSymptomMapping{ ID=4,disease=Cholera,symptom=Cough}
};
List<Symptom> symptoms = new List<Symptom> { Fever, Fever,Shevering };
List<Disease> diseases = GetDiseaseBySymptoms(symptoms, DiseaseDetails);
foreach (Disease disease in diseases)
{
Console.WriteLine("Disease Name :{0}", disease.Name);
}
Console.ReadLine();
}
class Disease
{
public int ID { get; set; }
public string Name { get; set; }
}
class Symptom
{
public int ID { get; set; }
public string Name { get; set; }
}
class DiseaseSymptomMapping
{
public int ID { get; set; }
public Disease disease { get; set; }
public Symptom symptom { get; set; }
}
static List<Disease> GetDiseaseBySymptoms(List<Symptom> symptoms,List<DiseaseSymptomMapping> DiseaseDetails)
{
var querytmp = from diseasedetails in DiseaseDetails
join symp in symptoms on diseasedetails.symptom equals symp in symptomsgrp
select new
{
DiseaseName= diseasedetails.Name,
Symptoms=symptomsgrp
};
foreach (var v in querytmp)
{
Console.WriteLine("{0}", v.DiseaseName);
}
return new List<Disease>();
}
}
Change in symptomsgrp to into symptomsgrp. And you get rid of the error by changing
DiseaseName = diseasedetails.Name
to
DiseaseName = diseasedetails.disease.Name

Getting an Enum to display on client side

I'm having hard time understanding how to convert an Enum value to it's corresponding name. My model is as follows:
public class CatalogRule
{
public int ID { get; set; }
[Display(Name = "Catalog"), Required]
public int CatalogID { get; set; }
[Display(Name = "Item Rule"), Required]
public ItemType ItemRule { get; set; }
public string Items { get; set; }
[Display(Name = "Price Rule"), Required]
public PriceType PriceRule { get; set; }
[Display(Name = "Value"), Column(TypeName = "MONEY")]
public decimal PriceValue { get; set; }
[Display(Name = "Exclusive?")]
public bool Exclude { get; set; }
}
public enum ItemType
{
Catalog,
Category,
Group,
Item
}
public enum PriceType
{
Catalog,
Price_A,
Price_B,
Price_C
}
A sample result from .net API:
[
{
$id: "1",
$type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
ID: 1,
CatalogID: 501981,
ItemRule: 0,
Items: "198",
PriceRule: 1,
PriceValue: 0.5,
Exclude: false
},
{
$id: "2",
$type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
ID: 2,
CatalogID: 501981,
ItemRule: 2,
Items: "9899",
PriceRule: 2,
PriceValue: 10.45,
Exclude: false
}
]
So in this example, I need to get Catalog for results[0].ItemRule & Price A for results[0].PriceRule. How can I accomplish this in BreezeJS??
This is easy to do in ASP.NET Web API, because it is an out-of-box feature in the default JSON serializer (Json.NET).
To see strings instead of enum numbers in JSON, just add an instance of StringEnumConverter to JSON serializer settings during app init:
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
jsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
UPDATE: Yep, you right, this is not help with Breeze.js. Ok, you can anyway do a little magic to make enums work like strings (while new version with fix is not released).
Create a custom ContextProvider which updates all integer enum values in metadata to strings. Here it is:
public class StringEnumEFContextProvider<T> : EFContextProvider<T>
where T : class, new()
{
protected override string BuildJsonMetadata()
{
XDocument xDoc;
if (Context is DbContext)
{
xDoc = GetCsdlFromDbContext(Context);
}
else
{
xDoc = GetCsdlFromObjectContext(Context);
}
var schemaNs = "http://schemas.microsoft.com/ado/2009/11/edm";
foreach (var enumType in xDoc.Descendants(XName.Get("EnumType", schemaNs)))
{
foreach (var member in enumType.Elements(XName.Get("Member", schemaNs)))
{
member.Attribute("Value").Value = member.Attribute("Name").Value;
}
}
return CsdlToJson(xDoc);
}
}
And use it instead of EFContextProvider in your Web API controllers:
private EFContextProvider<BreezeSampleContext> _contextProvider =
new StringEnumEFContextProvider<BreezeSampleContext>();
This works well for me with current Breeze.js version (1.1.3), although I haven't checked other scenarios, like validation...
UPDATE: To fix validation, change data type for enums in breeze.[min|debug].js, manually (DataType.fromEdmDataType function, dt = DataType.String; for enum) or replace default function during app init:
breeze.DataType.fromEdmDataType = function (typeName) {
var dt = null;
var parts = typeName.split(".");
if (parts.length > 1) {
var simpleName = parts[1];
if (simpleName === "image") {
// hack
dt = DataType.Byte;
} else if (parts.length == 2) {
dt = DataType.fromName(simpleName);
if (!dt) {
if (simpleName === "DateTimeOffset") {
dt = DataType.DateTime;
} else {
dt = DataType.Undefined;
}
}
} else {
// enum
dt = DataType.String; // THIS IS A FIX!
}
}
return dt;
};
Dirty, dirty hacks, I know... But that's the solution I found
There will be a new release out in the next few days where we "change" breeze's enum behavior ( i.e. break existing code with regards to enums). In the new release enums are serialized and queried by their .NET names instead of as integers. I will post back here when the new release is out.

Append OR subquery in Linq

I am trying to build a simple search against some entities (EF4, if that makes any difference). Passed into my search query is a list of criteria objects. The crieteria object looks like this:
public class ClaimSearchCirtieria
{
public Guid? FinancialYear { get; set; }
public bool AllClaimants { get; set; }
public IList<Guid> ClaimantIds { get; set; }
public bool AllExpenseCategories { get; set; }
public IList<ExpenseCategoryAndTypeCriteria> EpenseCategoryAndTypes { get; set; }
}
And the ExpenseCategoryAndTypeCriteria
public class ExpenseCategoryAndTypeCriteria
{
public Guid ExpenseCategory { get; set; }
public bool AllTypesInCatgeory { get; set; }
public IList<Guid> ExpenseTypes { get; set; }
}
Searching on financial years and claimants needs to be an AND query, then I need the expense categories and expense types to be appended as an OR sub query.
In essence I'm trying to do:
select *
from claims
where <financial year> AND <Claimants> AND (expense type 1 OR expense type 2 or expense category X)
So far I've got this:
public PagedSearchResult<Claim> Search(ClaimSearchCirtieria searchCriteria, int page, int pageSize)
{
var query = All();
if (searchCriteria.FinancialYear.HasValue)
{
query = from claim in query
where claim.FinancialYearId == searchCriteria.FinancialYear
select claim;
}
if (!searchCriteria.AllClaimants)
{
query = from claim in query
where searchCriteria.ClaimantIds.Contains(claim.ClaimantId)
select claim;
}
if (!searchCriteria.AllExpenseCategories)
{
foreach (var item in searchCriteria.EpenseCategoryAndTypes)
{
if (item.AllTypesInCatgeory)
{
//Just search on the category
query = query.Where(claim =>
(from transaction in claim.ClaimTransactions
where item.ExpenseCategory == transaction.ExpenseType.ExpenseCategoryId
select transaction).Count() > 0
);
}
else
{
//Search for the specified types
query = query.Where(claim =>
(from transaction in claim.ClaimTransactions
where item.ExpenseTypes.Contains(transaction.ExpenseTypeId)
select transaction).Count() > 0
);
}
}
}
return PagedSearchResult<Claim>.Build(query, pageSize, page);
}
What I'm currently seeing is that the last expense category requested is the only expense category I get results for. Also, looking at the code, it looks like I would expect this to be building a series of AND queries, rather that the required OR.
Any pointers?
You can do this with LINQKit's PredicateBuilder. You need to use AsExpandable() when composing Entity Framework queries.

Resources