Entity Framework using distinct substring and charindex - c#

I am trying to use SQL queries with Entity framework. But I didn't find out how to use it. Basically I try to use query as follow
SELECT DISTINCT
SUBSTRING(KeyStr, CHARINDEX('TYPE_', KeyStr) + 5, 5) Menu_Item,
Content, level
FROM
DB.dbo.StringDB

You can achieve that using the following code:
Assuming you have a class called Result which has the following declaration
public class Result
{
public string Menu_Item{get;set;}
public string Content{get;set;}
public string level{get;set;}
}
To retrieve the results using SQL Query:
var sql = #"SELECT DISTINCT
SUBSTRING(KeyStr, CHARINDEX('TYPE_', KeyStr) + 5, 5) Menu_Item,
Content, level
FROM
DB.dbo.StringDB";
var results = _dbContext.Database.SqlQuery<Result>(sql);
This should return a list of Result object

Related

How can i compare an array with sql query in c# code?

How can I compare an array with a SQL query in C#?
I have tried below code to resolve my problem but it was not worked.
In the below code data is the name of array which holds some types of data.
DataTable dt = context.getData("Select * from emp_detail where EState = any(" +data+ ")", CommandType.Text);
You can serialize the data array into a properly formatted string and change select command to something like that:
Select * from emp_detail where EState in ('a', 'b', ...)
This solution is only suitable for arrays with few items.
I think you could do this to get a list of strings to compare with:
using System.Linq;
namespace ExampleNamespase
{
public class SimpleClass
{
private class TypeExample
{
public string Property { get; }
}
private void CompareData(TypeExample[] exampleArray)
{
var items = string.Join(", ", exampleArray.Select(t => t.Property));
var sql = $"Select * from emp_detail where EState in ({items}) ";
}
}
}
Or so if you are using a simple list of strings:
private void CompareData(string[] exampleArray)
{
var items = string.Join(", ", exampleArray);
var sql = $"Select * from emp_detail where EState in ({items}) ";
}
To prevent injections, use the Dapper library:
using System.Data;
using Dapper;
namespace ExampleNamespase
{
public class SimpleClass
{
private void CompareData(string[] exampleArray, IDbConnection connection)
{
var sql = "Select * from emp_detail where EState in #items ";
var result = connection.Query<YourTypeClass>(sql, new { items = exampleArray });
}
}
}
Explanation:
The first example uses the Linq library to retrieve the properties of an object using the Select method, and the string.Join method to concatenate the resulting list into a comma-separated string.
The second example demonstrates the same approach, only with an array of strings, the same string.Join method is used to join.
In the third example, the Dapper library is used to execute the request, I believe that this method should be preferred, since helps to avoid SQL injection, and also simplifies the work with the database. To execute a query, we can pass a list of objects with which we want to compare values ​​in the database, and Dapper will be able to handle this itself. We just need to define variables with the # symbol in the request, and pass the object for processing, which will have attributes with the same names.
P.S. I apologize for my English))
Upd:
Try this:
private void CampareData(string[] exampleArray, IDbConnection connection)
{
var clearItems = exampleArray.Select(s => $"'{s}'").ToArray();
var sql = "Select * from emp_detail where EState in #items ";
var result = connection.Query<YourTypeClass>(sql, new { items = clearItems });
}
In this variant, we will wrap each item in quotes that are used by sql, and the query should contain something like: ... in ('item1', 'item2' ...)

How to Return Data from connection.QueryFirst in ASP.NET Core API

Hi Guys I am learning ASP.NET core
how to return data from SQLquery to json
current i am getting everything null in result
MY Controller Code snippet
[HttpGet]
[Route("GetData")]
public DataMaster GetData()
{
using (SqlConnection connection = new SqlConnection(_config.GetConnectionString("EmployeeDBConnection")))
{
var param = new DynamicParameters();
// param.Add("#prodtype", prodtype);
return connection.QueryFirst<DataMaster>(" Select producttype,servicetype,servicesubtype,count(*) from master_table group by producttype,servicetype,servicesubtype");
}
}
Response i am getting
{"callId":null,"callstartdate":null,"callstarttime":null,"calltype":null,"producttype":null,"servicetype":null,"callertype":null,"servicesubtype":null}
when i execute query in Database i am getting following response , how should return this response through API controller
please help.
It seems that you are using dapper & QueryFirst will Execute a query and map the first result to a dynamic list..
You should use Query : The raw SQL query can be executed using the Query method and map the result to a strongly typed list.
Use Query<DataMaster> instead of QueryFirst<DataMaster> and change return type to IEnumerable<DataMaster>.
As per comment you didn't get Count. I guess you are having Count property in DataMaster then you need to provide alias for count in query as count(*) AS Count then it will bind correctly.
[HttpGet]
[Route("GetData")]
public IEnumerable<DataMaster> GetData()
{
using (SqlConnection connection = new SqlConnection(_config.GetConnectionString("EmployeeDBConnection")))
{
var param = new DynamicParameters();
// param.Add("#prodtype", prodtype);
return connection.Query<DataMaster>(" Select producttype,servicetype,servicesubtype,count(*) AS Count from master_table group by producttype,servicetype,servicesubtype");
}
}

Dapper parameters not working

I'm trying to use the Dapper orm with the following simple query:
var sqlString = new StringBuilder();
sqlString.Append("select a.acct AccountNumber,");
sqlString.Append(" b.first_name FirstName,");
sqlString.Append(" b.last_name LastName,");
sqlString.Append(" a.rr RrNumber,");
sqlString.Append(" c.addr1 AddressLine1,");
sqlString.Append(" c.addr2 AddressLine2,");
sqlString.Append(" c.addr3 AddressLine3,");
sqlString.Append(" c.addr4 AddressLine4,");
sqlString.Append(" c.addr5 AddressLine5,");
sqlString.Append(" c.addr6 AddressLine6,");
sqlString.Append(" c.addr7 AddressLine7,");
sqlString.Append(" c.addr8 AddressLine8 ");
sqlString.Append("from (pub.mfclac as a left join pub.mfcl as b on a.client=b.client) ");
sqlString.Append("left join pub.mfclad as c on a.client=c.client ");
sqlString.Append("where a.acct = '#ZYX'");
var connection = new OdbcConnection(_connectionString);
var result = connection.Query(sqlString.ToString(),
new
{
ZYX = accountNumber
});
However when I execute this with an accountNumber known to exist, dapper returns nothing. So I tried to remove the quotes to verify that the parameter is in fact being replaced with the account number, however the error being returned from the server indicates a syntax error around "#ZYX". Which means dapper is not replacing the parameter with it's given value. Any ideas why this is happening? From the limited documentation out there, this should 'just work'.
Edit1
Couldn't get this to work. Using string.format to insert the parameter as a work around.
There are two issues here; firstly (although you note this in your question) where a.acct = '#ZYX', under SQL rules, does not make use of any parameter - it looks to match the literal string that happens to include an # sign. For SQL-Server (see note below), the correct usage would be where a.acct = #ZYX.
However! Since you are use OdbcConnection, named parameters do not apply. If you are actually connecting to something like SQL-Server, I would strongly recommend using the pure ADO.NET clients, which have better features and performance than ODBC. However, if ODBC is your only option: it does not use named parameters. Until a few days ago, this would have represented a major problem, but as per Passing query parameters in Dapper using OleDb, the code (but not yet the NuGet package) now supports ODBC. If you build from source (or wait for the next release), you should be able to use:
...
where a.acct = ?
in your command, and:
var result = connection.Query(sqlString.ToString(),
new {
anythingYouLike = accountNumber
});
Note that the name (anythingYouLike) is not used by ODBC, so can be... anything you like. In a more complex scenario, for example:
.Execute(sql, new { id = 123, name = "abc", when = DateTime.Now });
dapper uses some knowledge of how anonymous types are implemented to understand the original order of the values, so that they are added to the command in the correct sequence (id, name, when).
One final observation:
Which means dapper is not replacing the parameter with it's given value.
Dapper never replaces parameters with their given value. That is simply not the correct way to parameterize sql: the parameters are usually sent separately, ensuring:
there is no SQL injection risk
maximum query plan re-use
no issues of formatting
Note that some ADO.NET / ODBC providers could theoretically choose to implement things internally via replacement - but that is separate to dapper.
I landed here from dublicate question: Dapper must declare the scalar variable
Error: Must declare the scalar variable "#Name".
I created queries dynamically with this piece of code:
public static bool Insert<T>(T entity)
{
var tableName = entity.GetType().CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == nameof(TableAttribute))?.ConstructorArguments?.FirstOrDefault().Value as string;
if (string.IsNullOrEmpty(tableName))
throw new Exception($"Cannot save {entity.GetType().Name}. Database models should have [Table(\"tablename\")] attribute.");
DBSchema.TryGetValue(tableName.ToLower(), out var fields);
using (var con = new SqlConnection(ConnectionString))
{
con.Open();
var sql = $"INSERT INTO [{tableName}] (";
foreach (var field in fields.Where(x => x != "id"))
{
sql += $"[{field}]"+",";
}
sql = sql.TrimEnd(',');
sql += ")";
sql += " VALUES (";
foreach (var field in fields.Where(x => x != "id"))
{
sql += "#"+field + ",";
}
sql = sql.TrimEnd(',');
sql += ")";
var affectedRows = con.Execute(sql, entity);
return affectedRows > 0;
}
}
And I got the same error when my models was like this:
[Table("Users")]
public class User
{
public string Name;
public string Age;
}
I changed them to this:
[Table("Users")]
public class User
{
public string Name { get; set; }
public string Age { get; set; }
}
And it solved the problem for me.

how to convert int to string in Linq to entities

My Db column in a string (varchar) and i need to assign it to a int value.
I am using linq to query.Though the code compiles am getting an error at the run time .
Thanks in advance.
PFB my query :
var vlauesCap = from plan in entities.PA_RTM_CAP_Group
select new Business.PartnerProfile.LookUp
{
Id =Convert.ToInt32(plan.cap_group_code),
//(Int32)plan.cap_group_code,
Value = plan.cap_group_name
};
return vlauesCap.ToList();
The EF provider does not know how to translate Convert.ToInt() into SQL it can run against the database. Instead of doing the conversion on the server, you can pull the results back and do the conversion using linq to objects:
// the ToList() here causes the query to be executed on the server and
// the results are returned in a list of anonymous objects
var results = (from plan in entities.PA_RTM_CAP_Group
select new
{
Code = plan.cap_group_code,
Name = plan.cap_group_name
}).ToList();
// the conversion can now be done here using Linq to Objects
var vlauesCap = from r in results
select new Business.PartnerProfile.LookUp
{
Id = Convert.ToInt32(r.Code),
Value = r.Name
};
return vlauesCap.ToList();
You can't do this directly, what you can do is declare a private variable to handle your "mapped" value, and expose the unmapped property...
[Column(Name = "cap_group_code", Storage = "m_cap_group_code")]
private string m_cap_group_code;
public int cap_group_code {
get
{
return Int32.Parse(m_cap_group_code);
}
set
{
m_cap_group_code = value.ToString();
}
}
Try this:
var vlauesCap = from plan in entities.PA_RTM_CAP_Group
select new Business.PartnerProfile.LookUp
{
Id =Convert.ToInt32(plan.cap_group_code),
Convert.ToInt32(plan.cap_group_code),
Value = plan.cap_group_name
};
return vlauesCap.ToList();
Why aren't you using casting for such a purpose, which is a more effective way of achieving this.
Just replace Convert.ToInt32(plan.cap_group_code) with (int)plan.cap_group_code
Do remember, there should be a value in the string and is int, else it will show Exception. If you are not sure about it, then you can further expand the casting to use null coalesciting operator

Regex Replace to assist Orderby in LINQ

I'm using LINQ to SQL to pull records from a database, sort them by a string field, then perform some other work on them. Unfortunately the Name field that I'm sorting by comes out of the database like this
Name
ADAPT1
ADAPT10
ADAPT11
...
ADAPT2
ADAPT3
I'd like to sort the Name field in numerical order. Right now I'm using the Regex object to replace "ADAPT1" with "ADAPT01", etc. I then sort the records again using another LINQ query. The code I have for this looks like
var adaptationsUnsorted = from aun in dbContext.Adaptations
where aun.EventID == iep.EventID
select new Adaptation
{
StudentID = aun.StudentID,
EventID = aun.EventID,
Name = Regex.Replace(aun.Name,
#"ADAPT([0-9])$", #"ADAPT0$1"),
Value = aun.Value
};
var adaptationsSorted = from ast in adaptationsUnsorted
orderby ast.Name
select ast;
foreach(Adaptation adaptation in adaptationsSorted)
{
// do real work
}
The problem I have is that the foreach loop throws the exception
System.NotSupportedException was unhandled
Message="Method 'System.String Replace(System.String, System.String,
System.String)' has no supported translation to SQL."
Source="System.Data.Linq"
I'm also wondering if there's a cleaner way to do this with just one LINQ query. Any suggestions would be appreciated.
Force the hydration of the elements by enumerating the query (call ToList). From that point on, your operations will be against in-memory objects and those operations will not be translated into SQL.
List<Adaptation> result =
dbContext.Adaptation
.Where(aun => aun.EventID = iep.EventID)
.ToList();
result.ForEach(aun =>
aun.Name = Regex.Replace(aun.Name,
#"ADAPT([0-9])$", #"ADAPT0$1")
);
result = result.OrderBy(aun => aun.Name).ToList();
Implement a IComparer<string> with your logic:
var adaptationsUnsorted = from aun in dbContext.Adaptations
where aun.EventID == iep.EventID
select new Adaptation
{
StudentID = aun.StudentID,
EventID = aun.EventID,
Name = aun.Name,
Value = aun.Value
};
var adaptationsSorted = adaptationsUnsorted.ToList<Adaptation>().OrderBy(a => a.Name, new AdaptationComparer ());
foreach (Adaptation adaptation in adaptationsSorted)
{
// do real work
}
public class AdaptationComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string x1 = Regex.Replace(x, #"ADAPT([0-9])$", #"ADAPT0$1");
string y1 = Regex.Replace(y, #"ADAPT([0-9])$", #"ADAPT0$1");
return Comparer<string>.Default.Compare(x1, y1);
}
}
I didn't test this code but it should do the job.
I wonder if you can add a calculated+persisted+indexed field to the database, that does this for you. It would be fairly trivial to write a UDF that gets the value as an integer (just using string values), but then you can sort on this column at the database. This would allow you to use Skip and Take effectively, rather than constantly fetching all the data to the .NET code (which simply doesn't scale).

Categories