linq SingleorDefault - c#

I want to return a single row from the users table using domain account id as my primary and unique key
However when i use singleordefault and see its sql translation it performs entire select * from Users
my query is..
var user = base.SingleorDefault(t=>t.domainaccountid)
i want this to return just one row!

What is base ? Is it possible that you've coerced it to IEnumerable<T> at some point, rather than IQueryable<T>? that would cause this. Note that database composition is only possible when using IQueryable<T>, so if any of your methods have returned something other than this, composition will end.

You could try Where along with FirstOrDefault:
var user = base.Where(t => t.domainaccountid == 123).FirstOrDefault();

Try
var user = base.SingleorDefault(t=>t.domainaccountid==123);

SingleOrDefault looks for unique entries, it should be doing:
SELECT TOP 2 * FROM TABLE
It does this so that if it finds 2 results it will throw an exception as it is not unique.
If you don't care about finding it as a unique object, as you have other measure in place to prevent duplicates; or just don't care you can use FirstOrDefault in the following way:
array.FirstOrDefault(x => x.id == someOtherId);
This will perform the following:
SELECT TOP 1 * FROM TABLE
This will get your results quicker, especially in larger tables, because it will return as soon as the first result is found.

Related

How do I do an inner select in linq?

I have a database table called Customers. I run the following sql to get information about the first and second customer:
select FirstCustomerName, SecondCustomerName,
* from Customers where FirstCustomerName = SecondCustomerName
When I run this in sql it gives me what I want, so that one is ok. The problem is when I want to do the same thing in Linq in C#.
To achive the same thing with Linq I have tried this(still "doesn't work"):
InfoAboutBothCustomers = c.customers.FirstCustomerName == c.customers.SecondCustomerName.ToString()
Note: InfoAboutBothCustomers is an int in my ViewModel
So my question basically is how do the same thing in LINQ?
I am not sure what value you want in InfoAboutBothCustomers. Your SQL statement returns two values and you are saying that you want an int. c.customers.FirstCustomerName == c.customers.SecondCustomerName.ToString() will return a boolean to say if they are equal or not.
If you want the id or ids that match you criteria, try something like:
var ids = from cust in customers
where cust.FirstCustomerName == cust.SecondCustomerName
select cust.Id;
Alternatively you can use what is mentioned in the other answers, which is cleaner, but just be aware that FirstOrDefault will return the row of data. You can then specify the column that you want by doing something like this FirstOrDefault().Id;
Without sample it is difficult to provide any solution. But you can try this
InfoAboutBothCustomers = c.customers.Where(x=>x.FirstCustomerName == x.SecondCustomerName).FirstOrDefault()
In case of error /issue please share the sample.
Use .Where operation
InfoAboutBothCustomers = c.customers.Where(c => c.FirstCustomerName == c.SecondCustomerName).FirstOrDefault();

Query ODataV4 connected service with LINQ - Get last record from table

Im trying to query my OData webservice from a C# application.
When i do the following:
var SecurityDefs = from SD in nav.ICESecurityDefinition.Take(1)
orderby SD.Entry_No descending
select SD;
i get an exception because .top() and .orderby is not supposed to be used together.
I need to get the last record in the dataset and only the last.
The purpose is to get the last used entry number in a ledger and then continue creating new entries incrementing the found entry no.
I cant seem to find anything online that explains how to do this.
Its very important that the service only returns the last record from the feed since speed is paramount in this solution.
i get an exception because .top() and .orderby is not supposed to be used together.
Where did you read that? In general .top() or .Take() should ONLY be used in conjunction WITH .orderby(), otherwise the record being retrieved is not guaranteed to be repeatable or predictable.
Probably the compounding issue here is mixing query and fluent expression syntax, which is valid, but you have to understand the order of precedence.
Your syntax is taking 1 record, then applying a sort order... you might find it easier to start with a query like this:
// build your query
var SecurityDefsQuery = from SD in nav.ICESecurityDefinition
orderby SD.Entry_No descending
select SD;
// Take the first item from the list, if it exists, will be a single record.
var SecurityDefs = SecurityDefsQuery.FirstOrDefault();
// Take an array of only the first record if it exists
var SecurityDefsDeferred = SecurityDefsQuery.Take(1);
This can be executed on a single line using brackets, but you can see how the query is the same in both cases, SecurityDefs in this case is a single ICESecurityDefinition typed record, where as SecurityDefsDeferred is an IQueryable<ICESecurityDefinition> that only has a single record.
If you only need the record itself, you this one liner:
var SecurityDefs = (from SD in nav.ICESecurityDefinition
orderby SD.Entry_No descending
select SD).FirstOrDefault();
You can execute the same query using fluent notation as well:
var SecurityDefs = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
.FirstOrDefault();
In both cases, .Take(1) or .top() is being implemented through .FirstOrDefault(). You have indicated that speed is important, so use .First() or .FirstOrDefault() instead of .Single() or .SingleOrDefault() because the single variants will actually request .Take(2) and will throw an exception if it returns 1 or no results.
The OrDefault variants on both of these queries will not impact the performance of the query itself and should have negligble affect on your code, use the one that is appriate for your logic that uses the returned record and if you need to handle the case when there is no existing record.
If the record being returned has many columns, and you are only interested in the Entry_No column value, then perhaps you should simply query for that specific value itself:
Query expression:
var lastEntryNo = (from SD in nav.ICESecurityDefinition
orderby SD.Entry_No descending
select SD.Entry_No).FirstOrDefault();
Fluent expression:
var lastEntryNo = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
.Select(sd => sd.Entry_No)
.FirstOrDefault();
If Speed is paramount then look at providing a specific custom endpoint on the service to either serve the record or do not process the 'Entry_No` in the client at all, make that the job of the code that receives data from the client and compute it at the time the entries are inserted.
Making the query perform faster is not the silver bullet you might be looking for though, Even if this is highly optimised, your current pattern means that X number of clients could all call the service to get the current value of Entry_No, meaning all of them would start incrementing from the same value.
If you MUST increment the Entry_No from the client then you should look at putting a custom endpoint on the service to simply return the Next Entry_No to use. This should be optimistic meaning that you don't care if the Entry_No actually gets used in the end, but you can implement the end point such that every call will increment the field in the database and return the next value.
Its getting a bit beyond the scope of your initial post, but SQL Server now has support for Sequences that formalise this type of logic from a database and schema point of view, using Sequence simplifies how we can manage these types of incrementations from the client, because we no longer rely on the outcome of data updates to be comitted to the table before the client can increment the next record. (which is what your TOP, Order By Desc solution is trying to do.

RavenDB Any Query on Child Objects returns incorrect results

I have a RavenDB Query that searches for active users on a document.
The normal query looks like this:
var documents = session.Query<Document>().Where(d => d.Users.Any(u => u.Id == UserId && u.Active == true)).ToList();
The Automatically generated query looks like this:
from doc in docs.Documents
select new {
Users_Active = (
from docUsersItem in ((IEnumerable<dynamic>)doc.Users).DefaultIfEmpty()
select docUsersItem.Active).ToArray(),
Users_Id = (
from docUsersItem in ((IEnumerable<dynamic>)doc.Users).DefaultIfEmpty()
select docUsersItem.Id).ToArray()
}
However, this causes the query to return document which have the correct user, but that user is inactive, as long there is another active user on the document.
I suspect this is because the fields are indexed resulting as:
AssignedUsers_Id: [1, 2]
AssignedUsers_Active:[false, true]
And the query will match the Id in the array, and true in the Active array, even though they are at different indices in their respective arrays.
What changes do I need to make to the index to get this to return only documents that have the UserId correct AND is Active?
To avoid this in the future with automatic indexes, is there any way I can rewrite my LINQ query so it will index and perform correctly?
This is by design behavior with auto indexes. You can avoid this behavior by defining your own index, which will emit an index entry per user on the document.
The reason this is the default behavior for auto indexes is that in the vast majority of cases, it wouldn't matter to the user, but it has an extremely high potential cost on the server side, so we want the user to make an explicit decision about it.

Is there a wildcard for the .Take method in LINQ?

I am trying to create a method using LINQ that would take X ammount of products fron the DB, so I am using the .TAKE method for that.
The thing is, in situations I need to take all the products, so is there a wildcard I can give to .TAKE or some other method that would bring me all the products in the DB?
Also, what happens if I do a .TAKE (50) and there are only 10 products in the DB?
My code looks something like :
var ratingsToPick = context.RatingAndProducts
.ToList()
.OrderByDescending(c => c.WeightedRating)
.Take(pAmmount);
You could separate it to a separate call based on your flag:
IEnumerable<RatingAndProducts> ratingsToPick = context.RatingAndProducts
.OrderByDescending(c => c.WeightedRating);
if (!takeAll)
ratingsToPick = ratingsToPick.Take(pAmmount);
var results = ratingsToPick.ToList();
If you don't include the Take, then it will simply take everything.
Note that you may need to type your original query as IEnumerable<MyType> as OrderByDescending returns an IOrderedEnumerable and won't be reassignable from the Take call. (or you can simply work around this as appropriate based on your actual code)
Also, as #Rene147 pointed out, you should move your ToList to the end otherwise it will retrieve all items from the database every time and the OrderByDescending and Take are then actually operating on a List<> of objects in memory not performing it as a database query which I assume is unintended.
Regarding your second question if you perform a Take(50) but only 10 entries are available. That might depend on your database provider, but in my experience, they tend to be smart enough to not throw exceptions and will simply give you whatever number of items are available. (I would suggest you perform a quick test to make sure for your specific case)
Your current solution always takes all products from database. Because you are calling ToList(). After loading all products from database you are taking first N in memory. In order to conditionally load first N products, you need to build query
int? countToTake = 50;
var ratingsToPick = context.RatingAndProducts
.OrderByDescending(c => c.WeightedRating);
// conditionally take only first results
if (countToTake.HasValue)
ratingsToPick = ratingsToPick.Take(countToTake.Value);
var result = ratingsToPick.ToList(); // execute query

Simple query on linq

using linq, I want to check if a row exist on the DB. I just need a true\false return, no data.
I cant use the ExecuteQuery method because I dont have an entity (and I dont even need it)
I thought of doing something like this:
string command = "select * from myTable where X=Y"
var result = db.ExecuteCommand(command);
(db is my DataContext)
and expected the result to contain the number of affected rows. If different that -1 it would mean the record I'm looking for exists. But I always get -1. I imagine the ExecuteCommand method should only be used to tu run Insert, updates or deletes.
How can I run this simple check using linq
You can use the Any() operator. It will return true if the IEnumerable or IQueryable it is called on has at least one item (i.e. does it have any items).
If db is your data context, you should just do:
bool rowExists = dc.GetTable<myTable>().Any(row => row.X == row.Y);
In general, with LINQ to SQL (and Entity Framework), you rarely want to write SQL code directly.
Replace
select *
with
select count(*)
You're probably better off running SELECT COUNT(*) FROM myTable WHERE X=Y and checking if the single record returned is equal to zero or not

Categories