SQL Selection to Array in C# - c#

I am querying in C# for the first time, so please forgive my ignorance. I want to query a table, then place the results in an array/dict/dataframe to then be accessed later. I am unable to run the final code on my end, so this is more of an exercise in setting up the queries for when the final code (a chatbot) works.
Here is the code that should work to get boiling points and melting points seperately. Assume that casnumber is declared in advance (let's just call it str '753')
boiling_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point).FirstOrDefault();
melting_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.metling_point).FirstOrDefault();
How would I get the results of the query to an array/dict/dataframe instead?
dict = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point,
cdls.melting_point).FirstOrDefault();
Ideally, I would want {(boiling_point : 200F), (melting_point : 100F)} as output, or something similar in a table/df/array. There are 30+ attributes in the table, so a way to assign key-value pairs or create a dataframe from the query for each attribute queried would be ideal.

Get a list of Tuples like this
var tuples = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select (cdls.boiling_point, cdls.melting_point))
.ToList();
tuples will be a list of tuples (ex. List<(string boiling_point, string melting_point)>)
for (var tuple in tuples)
{
var boiling_point = tuple.boiling_point;
var melting_point= tuple.melting_point;
}

Related

LINQ 2 SQL - using a C# entity collection and SqlMethods.Like together

I have a collection of headers, each which contains a collection of objects, each of which contains a collection of metadata key value pairs. eg
> Header
> -> Object
> -> Key value pair
> -> Key value pair
> -> Object
> -> Key value pair
> -> Key value pair
I want to return all headers, which contain an object, which contains a certain key value pair in the metadata, using SQL wildcards (using SqlMethods.Like).
I have written a LINQ 2 SQL query below with two levels of subqueries which handles the scenario
string filePath = "ab%cd";
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
where mdp.Key == Constants.FilePath && SqlMethods.Like(mdp.Value.ToLower(), filePath))
select mdp
).Any()
select o).Any()
select h;
This works fine.
The problem arises when I have a list of possible search values to search on. Ie I want to find objects containing a metadata value from a list of possible matches, not just a single match. I tried the below.
var filePaths = new List<string> { "ab%cd", "ef%gh" };
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
where mdp.Key == Constants.FilePath && filePaths.Any(fp => SqlMethods.Like(mdp.Value.ToLower(), fp))
select mdp
).Any()
select o).Any()
select h;
but because SQLMethods.Like is contained within Filepaths.Any() it doesn't work. as it has to occur natively in the LINQ 2 SQL query.
How can I modify the top query to match, using SQL Like operator, so that it checks against a list of string search tokens, not a single one?
UPDATE: Error message below
Assert.IsFalse failed. An unexpected error occurred: LINQ to Entities
does not recognize the method 'Boolean Like(System.String,
System.String)' method, and this method cannot be translated into a
store expression.
The issue is, as you've mentioned, that once you put the SqlMethods.Like in the filePaths.Any it throws an exception.
That's because SqlMethods.Like is not supported in linq-to-entity, and filePath is an entity.
You need to, somehow, dynamically create multiple OR statements with SqlMethods.Like.
I've found a very similar question and an interesting answer that should help:
How can I add variable count of SqlMethods.Like() in one query?
The solution takes advantage of PredicateBuilder from C# 6.0 in a Nutshell.
I believe you could adapt your code into something like the following:
I didn't test the code, ofcourse.
var filePaths = new List<string> { "ab%cd", "ef%gh" };
var likeExpression = PredicateBuilder.False<MetaDataPairClassName>();
foreach (string filePath in filePaths)
{
likeExpression = likeExpression.Or(mdp =>
SqlMethods.Like(mdp.Value.ToLower(), filePath));
}
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
.Where(mdp.Key == Constants.FilePath)
.Where(likeExpression))
select mdp
).Any()
select o).Any()
select h;

String Comparison in LINQ to SQL result null

I have two string array and want to see if there are any intersection or not. I am using linq to sql in c# and fetch the database field and compare it with the user input as below :
string[] Materials = material.Split('-');
AllItems = (from item in AllItems
where item.Material.Split(',').Intersect(Materials).Count() != 0
select item).ToList();
Materials are user input string which has - delimiter and in database I have string with , delimiter.
I wonder why the result is always null. I mean the query result says there is no intersection but I check and there is.
Another alternative query that I used and take the same result was this :
string[] Materials = material.Split('-');
HashSet<string> stringSet = new HashSet<string>(Materials);
AllItems = (from item in AllItems
where item.Color.Split(',').Where(c => stringSet.Contains(c)).Count() != 0
select item).ToList();
I am so confused whats the problem with these queries. I should mention that the strings are UTF8 one and contains 2 bytes character in persian language, I guess maybe It's the problem but I don't know how to solve it.
Is there any solutions?
UPDATE (AllItems and Example) :
List<Item> AllItems = (from item in db.Items
select item).ToList();
Example of material => "ابی-قرمز-زرد"
Example of Item.Material => "ابی,سبز"
Update (Local Test) :
I test the same linq in some local string and using linq to object and the answer is correct !!! but in linq to sql and server string it always says that nothing found ! whats the problem?
I found out that, One of the Item's Color attribute was null and cause exception and return null. so I add a check to be not null before split and it works.
thanks all of you guys.

Not returning distinct records when use Distinct()

Using the following code I am not getting records distinct on the ID. Why is this?
List<string> products = new List<string>();
products.Add("13CONV");
products.Add("12CONV");
products.Add("11CONV");
products.Add("10CONV");
products.Add("09CONV");
products.Add("08CONV");
products.Add("07CONV");
var predicate = PredicateBuilder.True<Services>()
.And(m => products.Contains(m.Service));
var Results = from d in Services.Distinct()
.Where(predicate )
select d.ID;
Database table (Services) is:
ID Service
==
400 13Conv
401 13Conv
400 12Conv
400 07Conv
400 11Conv
Using the data above I get a count of 5 records when I would expect 2.
The ID field is a string in the DB.
It's Distinct, not DistinctByKey (method like that do not exists within LINQ), so all values within the row are checked for equality. With that check non of rows are equal. That's why they are all returned by query.
By the way - how would the database could decide, which row with given Key should be returned?
If you're trying to receive IDs only, and they should be distinct try that query:
var results = Services.Where(predicate).Select(s => s.ID).Distinct().ToList();
Update
According to question like this one there is known problem with LINQ to Entites and DISTINCT. Try that query instead:
Services.Where(predicate).GroupBy(s => s.Id).Select(g => g.Key).ToList();
You told it you wanted a distinct list of Service objects, not of service IDs (or names).
I'm not familiar with building predicates programmatically, but I think you'd do something like this:
var Results = (from d in Services.Where(Predicate)
select d.ID).Distinct();

Linq Union: How to add a literal value to the query?

I need to add a literal value to a query. My attempt
var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().Union(aa);
a.ToList().Dump(); // LinqPad's way of showing the values
In the above example, I get an error:
"Local sequence cannot be used in LINQ to SQL implementation
of query operators except the Contains() operator."
If I am using Entity Framework 4 for example, what could I add to the Union statement to always include the "seed" ID?
I am trying to produce SQL code like the following:
select distinct ID
from product
union
select 0 as ID
So later I can join the list to itself so I can find all values where the next highest value is not present (finding the lowest available ID in the set).
Edit: Original Linq Query to find lowest available ID
var skuQuery = Context.Products
.Where(p => p.sku > skuSeedStart &&
p.sku < skuSeedEnd)
.Select(p => p.sku).Distinct();
var lowestSkuAvailableList =
(from p1 in skuQuery
from p2 in skuQuery.Where(a => a == p1 + 1).DefaultIfEmpty()
where p2 == 0 // zero is default for long where it would be null
select p1).ToList();
var Answer = (lowestSkuAvailableList.Count == 0
? skuSeedStart :
lowestSkuAvailableList.Min()) + 1;
This code creates two SKU sets offset by one, then selects the SKU where the next highest doesn't exist. Afterward, it selects the minimum of that (lowest SKU where next highest is available).
For this to work, the seed must be in the set joined together.
Your problem is that your query is being turned entirely into a LINQ-to-SQL query, when what you need is a LINQ-to-SQL query with local manipulation on top of it.
The solution is to tell the compiler that you want to use LINQ-to-Objects after processing the query (in other words, change the extension method resolution to look at IEnumerable<T>, not IQueryable<T>). The easiest way to do this is to tack AsEnumerable() onto the end of your query, like so:
var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().AsEnumerable().Union(aa);
a.ToList().Dump(); // LinqPad's way of showing the values
Up front: not answering exactly the question you asked, but solving your problem in a different way.
How about this:
var a = Products.Select(p => p.sku).Distinct().ToList();
a.Add(0);
a.Dump(); // LinqPad's way of showing the values
You should create database table for storing constant values and pass query from this table to Union operator.
For example, let's imagine table "Defaults" with fields "Name" and "Value" with only one record ("SKU", 0).
Then you can rewrite your expression like this:
var zero = context.Defaults.Where(_=>_.Name == "SKU").Select(_=>_.Value);
var result = context.Products.Select(p => p.sku).Distinct().Union(zero).ToList();

Linq query with multiple where's [duplicate]

This question already has answers here:
Multiple WHERE clause in Linq
(3 answers)
Closed 2 years ago.
I am trying the to query my Status Update repository using the following
var result = (from s in _dataContext.StatusUpdates
where s.Username == "friend1" && s.Username == "friend2" etc...
select s).ToList();
Instead of using s.Username == "friendN" continuously is there anyway I can pass a list or array or something like that rather that specifying each one, or can I use a foreach loop in the middle of the query.
Thanks
If you only need to check whether the Username property has some specified value, you can create a list of the values and then use method such as All or Any to check if some condition holds for any/all elements of the array.
Your example looks a bit suspicious though - the user name s.Username cannot be equal to multiple different strings. Did you want to check whether it is equal to any of the (specified) names? That could be written like this:
var friends = new[] { "friend1", "friend2", ... };
var result =
from s in dc.StatusUpdates
where friends.Any(fr => s.Username == fr)
select s;
This returns all status updates such that the Username property is equal to any of the specified friend names (specified as an array, but you could use any IEnumerable<string>).
Yo could do it like this:
IQueryable<s> query= _dataContext.StatusUpdates;
foreach (var item in names)
{
query = query.Where(p=>p.Username == item);
}
List<s> result = query.ToList();
I think I mucked with some data types of yours but this should be close:
var names = new List<string>();
// populate names
var updates = new List<StatusUpdate>();
// populate updates
var result = (from s in updates
where names.Contains(s.ToString())
select s).ToList();

Categories