Slow linq query when looking for char(1) datatype using contains - entity-framework

I've got an old database with a char(1) Status column. I'm using code first and entity framework 4.3.1 to interact with my database. My Status column in my code first class is defined as follows:
[Column(TypeName = "char")]
public string Status { get; set; }
I'm writing a linq query to fetch all items with a Status of one of several values. The code looks something like this (although it's been simplified):
List<string> statusList = new List<string>() {"N","H","P"};
...
var entries = (from t in context.MyTable where statusList.Conains(t.Status)).ToList();
...
The SQL thats generated prefixes all the Status values with N making the query quite slow.
WHERE ([Extent1].[Status] IN (N'N', N'P', N'P'))
It seems to be because it's comparing unicode with non unicode so it can't use the index on the Status column.
I've had similar problems before in other linq queries, but I thought they were solved by putting [Column(TypeName = "char")] on the property.
Does anyone know how I prevent SQL from putting those N's in front of all my Status values? I tried making statusList a List of char, but then I needed to change the definition of the Status column to char in code first, but that threw errors.
Thanks
David

Are you on .NET Framework 4? I think this was fixed in EF5 core libraries shipped with .NET Framework 4.5. Here is a connect bug for this: http://connect.microsoft.com/VisualStudio/feedback/details/709906/entity-framework-linq-provider-defaulting-to-unicode-when-translating-string-contains-to-like-clause The connect bug also contains a workaround - use EntityFunctions.AsNonUnicode() function to force strings not to be Unicode which may be helpful if you can't move to .NET Framework 4.5

Related

Npgsql data type mapping of Character from Postgresql to .NET Core 2.0

In a PostgreSQL database I have a RFC column which is sort of a code to identify Enterprises and people in Mexico (for taxes purposes), code that I need to store in my database. The format of this 'code' it's like the next one:
AAAXXXXXXAXX -> where A's are letters and X's are numbers.
I want to store RFC column as primary key. As far as I've searched, Postgres Character data type is good for this, and I have the SQL query of it as pgAdmin4 generates:
rfc character(13) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT pk_empresas PRIMARY KEY (rfc)
But, inside Visual Studio using Package Manager Console and the next command:
Scaffold-DbContext "Host=localhost;Database=database;Username=pgadmin;Password=xxxx" Npgsql.EntityFrameworkCore.PostgreSQL -force
It generates my models that are mapped as the tables in my database.
The question here is, how can I work correctly if .NET char datatype only holds a single character and the property RFC is generated as follows?
public char Rfc { get; set; }
This first approach stores only the first character. I can see it in pgAdmin4
Database record saved
I've tried to change Rfc property data type(as I know that some .NET data types can match to others in PostgreSQL as we can see in the next link Npgsql Supported Types ) as string like this:
public string Rfc { get; set; }
But this Table is also related to another 4 or 5 Tables in my Database, and I get too many errors when I try to change the data type of this property in my model (as it is also related in models).
I have to say that I have tried this but it throws an exception.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries.
Edit 1:
I'm using Npgsql.EntityFrameworkCore.PostgreSQL version 2.0.1
This has been fixed for version 2.0.2 of the Npgsql EF Core provider which will be released very soon.
See https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/370 for the github issue.

Raw SQL with Entity Framework

I am trying to write a simple raw query with Entity Framework to my database:
[ResponseType(typeof(Customer))]
[Route("name/{name}")]
[HttpGet]
public List<Customer> GetCustomerName(string name)
{
//var results = db.Customers.SqlQuery("SELECT Name from dbo.Customer").Where(p => p.Name.Equals(name)).ToList();
var results = db.Customers.SqlQuery("SELECT Name from dbo.Customer WHERE Name = #Name",new SqlParameter("#Name",name)).ToList();
//var results = db.Customers.Where(p => p.Name.Equals(name));
return results;
}
The last Entity Framework query works just fine, but I want to do raw SQL to get something back simple because I have never gotten raw SQL with Entity Framework to work and I see all of these examples where people says it works for them. The top 2 var results do not work I get this error any help would be greatly appreciated. I am a Web API 2 newbie and I am just trying to learn it
So the error says a member of the type AccrRevAcct does not have a corresponding column. I am not sure what that means AccrRevAcct is a column on my database but so is Name and I just want the Name of my customer.
http://localhost:61280/api/Customers/name/1st MIDAMERICA CREDIT UNION
This is the call I make to my server and like I said it returns fine with the 3rd statement but that isn't raw SQL like I want to achieve. I only want to do this because I have some developers saying they can't get everything to work in EF I personally like it and haven't ran into this problem I want to show them fine just drop to raw SQL, but I need to show them I can make it work first lol.
If you are using SqlQuery on the DbSet you have to return a full instance. If you want to reshape the data like you are doing you need to use the SqlQuery<T> on the db.Database instead.
Example from https://msdn.microsoft.com/en-us/library/jj592907(v=vs.113).aspx
using (var context = new BloggingContext())
{
var blogNames = context.Database.SqlQuery<string>(
"SELECT Name FROM dbo.Blogs").ToList();
}
Honestly I think you are trying to solve the wrong problem. The last query is the one you should be using. If your developers can't get EF to work that is what needs to be fixed.

EF 6 database first: How to update stored procedures?

We are using Entity Framework 6.0.0 and use database first (like this) to generate code from tables and stored procedures. This seems to work great, except that changes in stored procedures are not reflected when updating or refreshing the model. Adding a column to a table is reflected, but not adding a field to a stored procedure.
It is interesting that if I go to the Model Browser, right click the stored procedure, select Add Function Import and click the button Get Column Information we can see the correct columns. This means that the model knows of the columns, but does not manage to update the generated code.
There is one workaround, and that is to delete the generated stored procedure before updating the model. This works as long as you have not made any edits on the stored procedure. Does anyone know of a way to avoid this workaround?
I am using Visual Studio 2013 with all the latest updates as of early December 2013.
Thanks in advance!
Update 1:
andersr's answer helped in one case, where the stored procedure used a temporary table, so i gave him +1, but it still does not solve the main problem of updating simple stored procedures.
Update 2:
shimron's comment below links to a question about the same issues in EF 3.5. It seems the same is still true for EF 6.0. Read it for an alternative way of doing it, but my conclusion as of now is that the simplest way of doing it is to delete the generated stored procedure before updating the model. Use partial classes if you want to do something fancy.
Based on this answer by DaveD, these steps address the issue:
In your .edmx, rt-click and select Model Browser.
Within the Model Browser (in VS 2015 default configuration, it is a tab within the Solution Explorer), expand Function Imports under the model.
Double-click your stored procedure.
Click the Update button next to Returns a Collection Of - Complex (if not returning a scalar or entity)
Click okay then save your .edmx to reflect field changes to your stored procedure throughout your project.
Does your stored procedures return data from temporary tables by any chance ? EF does not seem to support this, see EF4 - The selected stored procedure returns no columns for more information.
However, the stored procedure will as you observed, be available in the Model Browser. I did a quick test featuring the scenario described above. The stored procedure was generated in my context class, but the return type was an int rather than a complex type. See the link above for potential workarounds.
I just encountered this and my workaround (it is really nasty) was to create an if statement with a condition that will never be true at the top of the stored procedure which selects the same list of outputs as the query with explicit casting to the datatypes I want to return. This will assume nullability of your types, so to resolve that you wrap the cast in an ISNULL
For example, if your output has the columns:
UserId (int, not null)
RoleId (int, nullable)
FirstName (varchar(255), nullable)
Created (datetime, not null)
You would expect this to create a POCO like:
SomeClass {
public int UserId { get; set; }
public int? RoleId { get; set; }
public string FirstName { get; set; }
public DateTime Created { get; set; }
}
...But it doesn't and that's why we're here today. To get around this not working as expected, I put the following at the top of my SP (right after the 'AS'):
if(1=0)
begin
select
UserId = isnull((cast(0 as int)),0),
RoleId = cast(0 as int),
FirstName = cast(0 as varchar),
DateTime = isnull((cast(0 as datetime)),'')
end
It is horrible and ugly but it works for me every time. Hopefully we get a tooling update that resolves this soon...happened to me today with no temp tables in SQL Server 2016 w/VS2015...
Hope this helps somebody

Problem with ConcurrencyCheck attribute approach in EF

I've found two ways of concurrency checking for my entities in EF 4.1:
TimeStamp attribute for byte array
ConcurrencyCheck attribute for another types
The first one is very simple. You just mark byte array property as TimeStamp, create additional column in database and voila...
I've got a problem with the second method. Enity Framework has started generate sql script for concurrency check, when I marked the LastUpdateDate property.
Property:
[ConcurrencyCheck]
public DateTime LastUpdateDate { get; set; }
Sql:
select
...
where (([Id] = #3) and ([LastUpdateDate] = #4))
...
#4='value'
But EF does not generate sql script for updating the value of LastUpdateDate?
Is it possible to say EF to update the LastUpdateDate after concurrency checking without triggers or something like this?
And the second question:
What is the best practice of using concurrency checking in EF when you have something like LastUpdateDate property(property will be displayed in UI)? Is it better to check concurency using LastUpdateDate and avoid creating of addtional column for TimeStamp in your tables or
create additional TimeStamp property and renounce of the using DateTime property for concurrency checking?
Have you tried to use a rowversion (timestamp) instead of the DateTime datatype to check for concurency?
I would use the timestamp, because you are sure that the system will update it for you. Further more the value will be very precice.
The following blog posts will give you more information about how to map a timestamp.
The first one shows how to use the timestamp as a concurrency check.
Code First Optimistic Concurrency with Fluent Assertions
Round tripping a timestamp field with EF4.1 Code First and MVC 3

GUID or int entity key with SQL Compact/EF4?

This is a follow-up to an earlier question I posted on EF4 entity keys with SQL Compact. SQL Compact doesn't allow server-generated identity keys, so I am left with creating my own keys as objects are added to the ObjectContext. My first choice would be an integer key, and the previous answer linked to a blog post that shows an extension method that uses the Max operator with a selector expression to find the next available key:
public static TResult NextId<TSource, TResult>(this ObjectSet<TSource> table, Expression<Func<TSource, TResult>> selector)
where TSource : class
{
TResult lastId = table.Any() ? table.Max(selector) : default(TResult);
if (lastId is int)
{
lastId = (TResult)(object)(((int)(object)lastId) + 1);
}
return lastId;
}
Here's my take on the extension method: It will work fine if the ObjectContext that I am working with has an unfiltered entity set. In that case, the ObjectContext will contain all rows from the data table, and I will get an accurate result. But if the entity set is the result of a query filter, the method will return the last entity key in the filtered entity set, which will not necessarily be the last key in the data table. So I think the extension method won't really work.
At this point, the obvious solution seems to be to simply use a GUID as the entity key. That way, I only need to call Guid.NewGuid() method to set the ID property before I add a new entity to my ObjectContext.
Here is my question: Is there a simple way of getting the last primary key in the data store from EF4 (without having to create a second ObjectContext for that purpose)? Any other reason not to take the easy way out and simply use a GUID? Thanks for your help.
I ended up going with a GUID.
The size/performance issues aren't
critical (or even noticeable) with SQL Compact, since
it is a local, single-user system.
It's not like the app will be
managing an airline reservation
system.
And at least at this point, there
seems to be no way around the "no
server-generated keys" limitation of
the SQL Compact/EF4 stack. If someone has a clever hack, I'm still open to it.
That doesn't mean I would take the same approach in SQL Server or SQL Express. I still have a definite preference for integer keys, and SQL Compact's bigger siblings allow them in conjunction with EF4.
Use a Guid. AutoIncrement is not supported on Compact Framework with Entity Framework.
Also, if you ever want to create a application which uses multiple data sources, int PK's are going to fall apart on you very, very quickly.
With Guid's, you can juse call Guid.NewGuid() to get a new key.
With int's, you have to hit the database to get a valid key.
If you store data in multiple databases, int PK's will cause conflicts.
What I've done for SQL CE before, and I assume we have a single application accessing the database, is to calculate the MAX value on startup and put it in a static variable. You can now hand out sequential values easily and you can make the code to generate them thread safe very easily.
One reason to avoid Guids would be size = memory and storage space consumption.
You could also query SQL Compact metadata like so:
SELECT AUTOINC_NEXT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Categories' AND AUTOINC_NEXT IS NOT NULL