I am trying to get a list from Locations table and exclude the Locations already assigned to a user. I am trying to using Linq FromSQL. If I hard code the user.Id parameter the query works, when I use the user.Id variable it does not work. Query returns all records. When I run the debugger, the user.Id variable is correct. Here is my code...
ApplicationUser user = await _userManager.FindByNameAsync(Id);
var unassignedLocations = await _context.Location
.FromSql($"SELECT * FROM Locations WHERE Id NOT IN (SELECT LocationId FROM UserLocations WHERE UserID='{user.Id}')")
.OrderBy(l => l.Name)
.ToListAsync();
Locations = new SelectList(unassignedLocations, "Id", "Name");
The problem are the enclosing quotes around the value
UserID='{user.Id}'
When using FromSql method overload with interpolated SQL string, rather than embedding the value inside the SQL string (which would allow SQL injection attacks), EF Core will bind a parameter for every placeholder inside the string - in this case, single parameter with value = user.Id.
Hence you have to access the value directly w/o enclosing it with quotes like constant:
WHERE UserID={user.Id}
Related
I'm trying to retrieve all fields from two joined tables to any kind of a c# object.
So I'm trying to run this code:
var query = #$"EXEC('select *
from persons p join students s on p.id=s.id
where p.id = 21')";
var result = _context.Database.SqlQuery<?>(query).ToList();
But I don't get what should be instead of the question mark.
I've tried List<object> and Dictionary<string,string> but since I couldn't get exactly how this is being mapped, I don't understand to what it can be mapped.
There is a somewhat similar question here but its solution only addresses two columns, and it apparently doesn't support returning nulls.
You can try creating a stored procedure or a function in the SQL level.
Then, just select then generated table / result.
So, you already have an idea of what class it is.
I frequently use the dynamic type like this :
var lst = _context.Database.SqlQuery<dynamic>(query).ToList();
foreach (var item in lst)
{
var myVar = item.myfieldName;
}
It may be preferable to name each field in your query instead of using select *.
I am using dapper and a lambda expression in order to retrieve data from the database. Instead of building a ton of overloaded expressions, i want to pass in a single database object and have my lambda expression match on the closest or first object found.
public static User GetUser(User pUser)
{
using (IDbConnection connection = new SqlConnection(Connection))
{
return connection.Query<User>("SELECT * FROM dbo.USERS").(m => m == pUser);
}
}
In the example above, you can see I am passing a "User" object into the function, this user object could be 50% of what the exepected object is. for example, if the object had 2 strings, the ID and the users name. But I only knew the users name. I would create a new user as an ref or out param and have the query fill in the missing data.
Thoughts? I could create a ton over overloaded functions with duplated code like GetUserByID, and GetUserByName but that seems redundant.
You need to re-write the query. Kindly provide the structure of dbo.Users table.
Place filter logic inside of query and use table columns to match records instead of whole object.
public static User GetUser(User pUser)
{
using (IDbConnection connection = new SqlConnection(Connection))
{
return connection.Query<User>("Select * FROM dbo.Users where userID = #UserId", pUser).FirstOrDefault();
}
}
We can use the below query to retrieve specific columns using Entity Framework:
var result = context.Contents.Where(c => c.CatalogId == "ABC")
.Select(c => new {c.ContentId, c.ContentName});
I want to pass the column names during runtime.
Can I pass these column names {c.ContentId, c.ContentName} dynamically at runtime.
Thanks
You have to construct a lambda expression at runtime for that to work. There are libraries such as Dynamic LINQ that do some of the work for you, and the Expression APIs themselves aren't too bad to be honest, but I feel it becomes more effort than it is worth at that point. The simplest way is just to drop back down to plain parametrized SQL:
var fields = new[] { "ContentId", "ContentName" };
var q = "SELECT " + string.Join(", ", fields) + " WHERE CatalogId = #Id";
var result = context.Database.SqlQuery<dynamic>(q, new SqlParameter("Id", "ABC"));
Note: Be absolutely certain that the field names here are not coming from user input, because if you don't do that, you're opening yourself up to SQL injection. There are ways to contort the query a bit to avoid SQL injection (add a variable in the query that is parametrized, do a switch case on the variable to select fields), but that is beyond the scope of this answer. Best to entirely avoid interpolating strings from unknown sources into your SQL.
I'm attempting to pass a string of numbers into a query that will run against our AS400 connection however it doesn't seem that my value is actually making it to the query. I am returning a result when I debug to the point of the parameter so I know I'm getting my number.
var command = new OleDbCommand("SELECT UMACT, UMCUS, UMNAM, UMAD1, UMAD2, UMAD3, UMZIP, UMOPH, UMSLC FROM CFFILES.UMST WHERE trim(UMEMT) = '?' ", connection);
//Test meter number: 59115796
connection.Open();
OleDbParameterCollection paramCollection = command.Parameters;
paramCollection.Add(meternumber.ToString(), OleDbType.LongVarChar);
When I pass a number directly into the query it returns a perfect result however when I try to pass a number from the parameter it returns null.
Here is the variable itself that I know is being passed to my parameter that I created above because I get a result when I debug to that line.
public IEnumerable<CustomerInfoModel> GetCustomerInfo()
{
int meternumber = 59115796;
getAS400Data(meternumber);
return customerList;
}
For my AS400 query to work I have to have the ticks around the ? in the query so I'm not sure if that is perhaps causing the issue.
You have the call to Add method wrong. The first parameter of Add is the Name of the parameter, the second is the DataType and finally you should set the value of the parameter in this way
OleDbParameterCollection paramCollection = command.Parameters;
paramCollection.Add("whatever", OleDbType.LongVarChar).Value = meternumber.ToString();
See OleDbParameterCollection.Add
And no, you shouldn't add ticks around the question mark placeholder. If you do you transform your placeholder in a literal string and obviously you don't have any row with a question mark as value.
A final note, in OleDb parameters doesn't have a name, but when you add them to your collection you should provide one so you are free to choose whatever you like for the name. Just remember to keep them in the same order in which the placeholders (?) appears in your query string
Suppose that I want to create an SQL SELECT statement dynamically with reflection on primary key. I search in the table for primary keys and then, I make the statement.
Problem is, I don't know the type of fields that compose the primary key before getting them. So, if it's a string or date, I must add quotation marks but not if it's an int.
Atm, I am doing like that :
var type = field.GetType().Name;
if (type.ToLower().StartsWith("string") || type.ToLower().StartsWith("date"))
{
field = "\"" + field + "\"";
} else if (type.ToLower().StartsWith("char"))
{
field = "\'" + field + "\'";
}
With this code, I can handle some SQL types but there are a lot more.
My problem is that it's combined with LinQ. I got a DataContext object and a generic type table from the context. And context.ExecuteQuery only allows parameters to be passed has values. I also tried with Dynamic LinQ but I got the same problem
Does anyone know a better solution?
That is simply the wrong way to write SQL. Parameterize it and all these problems evaporate (as do problems with "which date format to use", etc. And of course the biggie: SQL injection.
Then it just becomes a case of adding #whatever into the TSQL, and using cmd.Parameters.AddWithValue("whatever", field) (or similar).
Update (from comments): since you mention you are using DataContext.ExecuteQuery, this becomes easier: that method is fully parameterized using the string.Format convention, i.e.
object field = ...;
var obj = db.ExecuteQuery<SomeType>(
"select * from SomeTable where Id = {0}", field).ToList(); // or Single etc
No string conversions necessary.
(the last parameter is a params object[], so you can either pass multiple discreet terms, or you can populate an object[] and pass that, if the number of terms is not fixed at compile-time; each term in the array maps by (zero-based) index to the {0}, {1}, {2}... etc token in the query)
Have you tried with parameters? For instance if you are using SQLServer as a database and you want to do this query:
"SELECT * FROM someTable WHERE id = " + field;
Then you should use sometething like this:
"SELECT * FROM someTable WHERE id = #field"
and add parameter to your command:
SqlParameter param1 = new SqlParameter("#field", field);
command.Parameters.Add(param1);
EDIT: Watch out that for different database providers the syntax for the SQL query is different, the same for the Access would be
"SELECT * FROM someTable WHERE id = ?";
command.Parameters.AddWithValue("field", field);