insert from linq to sql with join - c#

I have the following query
var listOfFollowers = (from a in db.UserLinks
where a.TargetUserID == TargetUserID && a.LinkStatusTypeID == 2
join b in db.UserNotifications on (int)a.OriginUserID equals b.TargetUserID
select b);
then I want to update once column on each row ( or object) returned
foreach (var a in listOfFollowers)
{
a.UserNotifications += HappeningID.ToString() + "|";
}
db.SubmitChanges();
The query seems to work , and when I put the generated SQL into SSMS it works fine , but when I run the entire code I get exception for trying to cast to int, don't make too much sense.
Is this ok , to do a query using a join , but only returning one table , change one property, then submitchanges?

The reason you are getting can't cast exception is that in the LINQ statement it is invalid to do cast. Other things which we can't do is to use regular method calls such as toString()
(int)a.OriginUserID is not allowed in
var listOfFollowers = (from a in db.UserLinks
where a.TargetUserID == TargetUserID && a.LinkStatusTypeID == 2
join b in db.UserNotifications on (int)a.OriginUserID equals b.TargetUserID
select b);
This problem will occur because parser tries to convert it into a equivalent SQL but doesn't find any equivalent. Other such cases are when you try to invoke toString(). Several Good responses here:
linq-to-entities-does-not-recognize-the-method
For your current scenario, I believe you have to
1. get the results from first query
2. cast the value
3. Make the second LINQ query
Hope this helps!

Most likely, problem occures in this piece of code (int)a.OriginUserID.
Try remove casting or use SqlFunctions.StringConvert() to compare strings.

Related

Multiple database row deletes in a single ActionResult? (ASP.NET) [duplicate]

I'm currently using a single query in two places to get a row from a database.
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p).Single();
The query is fine when retrieving the row to put data in to the text boxes, but it returns an error "Sequence contains no elements" when used to retrieve the row in order to edit it and put it back in to the database. I can't understand why it might find an appropriate row in one instance but not another.
(Using ASP.NET MVC and LINQ)
From "Fixing LINQ Error: Sequence contains no elements":
When you get the LINQ error "Sequence contains no elements", this is usually because you are using the First() or Single() command rather than FirstOrDefault() and SingleOrDefault().
This can also be caused by the following commands:
FirstAsync()
SingleAsync()
Last()
LastAsync()
Max()
Min()
Average()
Aggregate()
Please use
.FirstOrDefault()
because if in the first row of the result there is no info this instruction goes to the default info.
Well, what is ID here? In particular, is it a local variable? There are some scope / capture issues, which mean that it may be desirable to use a second variable copy, just for the query:
var id = ID;
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == id
select p).Single();
Also; if this is LINQ-to-SQL, then in the current version you get a slightly better behaviour if you use the form:
var id = ID;
BlogPost post = dc.BlogPosts.Single(p => p.BlogPostID == id);
In addition to everything else that has been said, you can call DefaultIfEmpty() before you call Single(). This will ensure that your sequence contains something and thereby averts the InvalidOperationException "Sequence contains no elements". For example:
BlogPost post = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p).DefaultIfEmpty().Single();
This will solve the problem,
var blogPosts = (from p in dc.BlogPosts
where p.BlogPostID == ID
select p);
if(blogPosts.Any())
{
var post = blogPosts.Single();
}
I had a similar situation on a function that calculates the average.
Example:
ws.Cells[lastRow, startingmonths].Value = lstMediaValues.Average();
Case Solved:
ws.Cells[lastRow, startingmonths].Value = lstMediaValues.Count == 0 ? 0 : lstMediaValues.Average();
Reason for error:
The query from p in dc.BlogPosts where p.BlogPostID == ID select p returns a sequence.
Single() tries to retrieve an element from the sequence returned in step1.
As per the exception - The sequence returned in step1 contains no elements.
Single() tries to retrieve an element from the sequence returned in step1 which contains no elements.
Since Single() is not able to fetch a single element from the sequence returned in step1, it throws an error.
Fix:
Make sure the query (from p in dc.BlogPosts where p.BlogPostID == ID select p)
returns a sequence with at least one element.

Linq to get data from a table but not if in another table?

Because of a poor design on our database I have to write a complex query to get my data.
I need to get all valid data from a table_1. In other works I need to get each valid row of my table_1. I don't have a simple valid or invalid column in my table_1. This information is stored in a table_2. Table_2 contains all invalid row with the error message.
Let say the data I need to retrieve are orders. For my example notice that OrderNo is the number of an order. So I can have multiple line, version, of this order in table_1 and I can also have multiple line of error on this order in table_2. So I will also have to use a version number.
I already tried this:
table_1.Where(y => (y.OrderNo == "1234"));
table_2.Where(y => (y.OrderNo == "1234")).Select(y => y.Version).Distinct();
And I think I need to do something like this:
var errorList = table_2.Where(y => (y.OrderNo == "1234")).Select(y => y.Version).Distinct();
table_1.Where(y => (y.OrderNo == "1234" && y.Version.NOT_IN(erriList)));
Could you help me?
I suppose you are searching for Contains function with ! symbol (logical negation operator). Like this:
var errorList = table_2.Where(y => y.OrderNo == "1234")
.Select(y => y.Version);
var res = table_1.Where(y => y.OrderNo == "1234"
//here you get only rows that doesn't represent in errorList
&& !errorList.Contains(y.Version));
to get data from a table but not if in another table
This is called antijoin. While you can use Contains and Any based approaches presented in the other answers, usually you'll get the best performance by using the classic SQL approach - LEFT OUTER JOIN combined with checking the right side for NULL.
Which in LINQ looks like this:
var query =
from t1 in table_1
//where t1.OrderNo == "1234"
join t2 in table_2 on t1.OrderNo equals t2.OrderNo into t2group
from t2 in t2group.DefaultIfEmpty()
where t2 == null
select t1;
Actually when you use OrderNo filter, most probably there will not be a noticeable speed difference between this and other queries. The main benefit of the above would be if you remove that filter, although many nowadays SQL query optimizers are able to derive one and the same execution plan regardless of whether the query uses JOIN / IN / EXISTS constructs.
How about this:
var validRows = table1
.Where(t1 => !table2
.Any(t2 => t1.OrderNo == t2.OrderNo &&
t1.Version == t2.Version));
Note that this is far more efficient in SQL unless you're using something fancy that translates the expression to SQL.

LINQ to SQL join generates SQL which joins on IS NULL

I am not good at Linq expression, today I am running into one weird issue as the below of inner join statement,
var orders = (from q in dao.CurrentDBContext.New_OrderForm
join d in dao.CurrentDBContext.New_OrderGoodsDetail on q.billNum equals d.billNum
select new
{
q.billNum,
q.orderSource,
q.sourceOddNum
d.PPT
}
While I traced the linq statement, I am confused of that Entity Framework will convert the linq statement to the below sql statment
SELECT
[Extent1].[billNum] AS [billNum],
[Extent1].[orderSource] AS [orderSource],
[Extent1].[sourceOddNum] AS [sourceOddNum],
[Extent2].[PPT] AS [PPT]
FROM [dbo].[New_OrderForm] AS [Extent1]
INNER JOIN [dbo].[New_OrderGoodsDetail] AS [Extent2]
ON ([Extent1].[billNum] = [Extent2].[billNum]) OR
(([Extent1].[billNum] IS NULL) AND ([Extent2].[billNum] IS NULL))
Do you know why the below SQL segment did automatically append?
OR (([Extent1].[billNum] IS NULL) AND ([Extent2].[billNum] IS NULL)"
I don't expect that the above automatically append, since it did slow down SQL performance. Any suggestions?
Here is what you can do in case you cannot change the billNum columns to be non nullable.
First, set the option mentioned by #Giorgi
class CurrentDBContext
{
public CurrentDBContext()
{
Configuration.UseDatabaseNullSemantics = true;
// ...
}
}
Then change the LINQ query to not use join, but simple where like this
var orders = (from q in dao.CurrentDBContext.New_OrderForm
from d in dao.CurrentDBContext.New_OrderGoodsDetail
where q.billNum == d.billNum
select ...
The result will be the exact SQL query as the one you've shown (with JOIN!) without the OR part.
It seems that Linq translates q.billNum equals d.billNum is such a way that it also includes a valid match in case both q.billNum and d.billNum are NULL (in SQL NULL is never equal to NULL, hence the OR in your query).
Making both fields non-nullable would be the best solution, provided both fields can never be NULL.
If this is not the case, you could also try to add a where clause in your Linq statement to specifiy that both q.billNum and d.billNum cannot be NULL. With any luck, Linq will recognize that nullable values are not possible.
Note: If you are working with Oracle you should check for empty strings as well as NULL (empty string is equivalent to NULL). Empty strings should be fine as a valid value in SQL Server.
As the above did not help, you could try to write the query yourself. If I'm not mistaking it would be something along the following lines (assuming var is an List<Order> in your example code - the results of your query should match the class you are using):
StringBuilder query = new StringBuilder();
query.AppendLine("SELECT [Extent1].[billNum] AS [billNum],");
query.AppendLine(" [Extent1].[orderSource] AS [orderSource],");
query.AppendLine(" [Extent1].[sourceOddNum] AS [sourceOddNum],");
query.AppendLine(" [Extent2].[PPT] AS [PPT]");
query.AppendLine("FROM [dbo].[New_OrderForm] AS [Extent1]");
query.AppendLine("INNER JOIN [dbo].[New_OrderGoodsDetail] AS [Extent2] ON [Extent1].[billNum] = [Extent2].[billNum]");
List<Order> orders = DbContext.Database.SqlQuery<Order>(query.ToString()).ToList();
I have used similar workarounds to get around performance issues in the past.
If you are using EF6 try setting
context.Configuration.UseDatabaseNullSemantics = true;
and it will not generate NULL checks for those columns.
According to documentation
For example (operand1 == operand2) will be translated as: (operand1 = operand2) if UseDatabaseNullSemantics is true, respectively (((operand1 = operand2) AND (NOT (operand1 IS NULL OR operand2 IS NULL))) OR ((operand1 IS NULL) AND (operand2 IS NULL))) if UseDatabaseNullSemantics is false.
Following on from #Giorgi's answer, the UseDatabaseNullSemantics flag will not work with the equals keyword - only the == operand. Thus in order to get round this and ensure the join on billNum is not part of the OR clause this approach should work (in conjunction with the UseDatabaseNullSemantics flag):
var orders = (from q in dao.CurrentDBContext.New_OrderForm
from d in dao.CurrentDBContext.New_OrderGoodsDetail
where q.billNum == d.billNum
select new
{
q.billNum,
q.orderSource,
q.sourceOddNum
d.PPT
}
This will generate the JOIN without the OR.

converting int to string in linq to entites

My Code is :
var currency = (from ac in db.shop
join cur in db.books
on ac.CODE equals cur.CODE.ToString() //here is the Error
// because "ac.code is type strig" & "cur.code is type long
where ac.ID == merchantId
select new Currency()
{
ShopCode = ac.CODE,
PosCode = ac.POSCODE,
}).ToList();
I found that .ToString(), SqlFunctions.StringConvert(long) are not working in the join query conditions but working in 'select' area in the query.
However Devart.Data.Oracle.Entity.OracleFunctions.ToChar((long)cur.CODE) is working fine. Since I am using entity framework it shouldn't have problems with particular DB types (i.e. oracle or sql server). It should work even I change from oracle to sql in future.
Please give me a solution for this.
Did you try casting on this.
Try : ac.CODE equals (string)cur.CODE
You can create a VIEW Currency on the database and perform the query on the view.
Here is the list of supported method for Linq to Entities, if conversion is not supported you can not execute it.
http://msdn.microsoft.com/en-us/library/bb738681.aspx
The problem is, that EF is trying to convert whole your expression into T-SQL query.
So it will look similar to this:
select ac.CODE, cur.CODE from shop ac
inner join books cur on ac.CODE = cur.CODE
Here is your problem. CODE fields have diffent types and server can't join on them.
In T-SQL you can use CAST, but since EF don't support such operation you can't do anything.
And afterall, why do you store those codes in string? If you have such a query, then in most cases there is some problem with your DB schema.
I would suggest you to look at the schema and refactor it, so CODE is always of type long. Then everything will work.
If you still really want to use different types for you columns. You can look at this question, to see how to execute CAST Convert String to Int in EF 4.0
this should solve your problem:
var currency = (from ac in db.shop
join cur in db.books
let codestr = cur.CODE.ToString()
on ac.CODE equals codestr
where ac.ID == merchantId
select new Currency()
{
ShopCode = ac.CODE,
PosCode = ac.POSCODE,
}).ToList();

Cannot implicitly convert type 'System.Linq.IQueryable<int>' to 'int?'

var cityList = from country in
doc.Element("result")
.Element("cities")
.Descendants("city")
select new {
Name = country.Element("name").Value,
Code = country.Element("code").Value,
CountryCode = int.Parse(country
.Element("countrycode")
.Value)
};
foreach(var citee in cityList)
{
City city = new City();
city.CountryID = from cnt in db.Countries
where cnt.DOTWInternalID == citee.CountryCode
select cnt.ID;
}
I'm getting an error on the second query as seen in the title of this post. I tried converting to int to nullable int but nothing worked. Help me, guys.
Thanks
it will return an iQueryable, you will need to do something like using the First
cit.CountryID = db.Countries.First(a=>a.DOTWInternalID == citee.CountryCode).ID
It has elapsed a long time since the last update to the post but i think it's worth improving the solution.
In my opinion the solutions posted for this particular scenario are not the best way in terms of performace to get the ID you need. A better solution is as follows.
db.Countries.Where(a=>a.DOTWInternalID == citee.CountryCode)
.Select(a => a.ID).FirstOrDefault();
The previous statemants basically runs a SQL query similar to the following one:
SELECT TOP (1) ID
FROM [dbo].[Countries]
WHERE DOTWInternalID = 123
The proposed solutions work but basically do a "SELECT *" to create the entity with all the values and then obtain the ID from the object just created.
You can use Linqpad to actually see the generated SQL and tune up LINQ queries or Lambdas.
Hope it helps to some others that get to this post.
Here is the problem and solution
from cnt in db.Countries where cnt.DOTWInternalID == citee.CountryCode select cnt.ID part. If you omit the ID then it returns a Generic IEnumerable with Country(hoping that you have Country class). So what you have to do is first return the select criteria and select the first row then the ID field. Same like shown below.
cit.CountryID = (from cnt in db.Countries where cnt.DOTWInternalID == citee.CountryCode select cnt).First<Country>().ID;
This will solve your problem.
IQueryable is not a single int - but a query that can represent a collection.
As the error message says, your Linq query returns an System.Linq.IQueryable (for all intents and purposes a collection of ints). If you'd like to get one of them, you can either call First or ElementAt(n) to get the n'th element.
cit.CountryID = db.Countries.First(a=>a.DOTWInternalID == citee.CountryCode).ID

Categories

Resources