Mapping enums while using dapper - enums

I have the following problem. I am using Dapper to connect to a database, the field that is a varchar in the database is an enum in my object. There is no problem for Dapper to map the database object to my DTO if the enum has the same name as the string in the database. Unfortunately, the strings in the database are not very user friendly and I was wondering if there is a way to map them or convert (only enums) to use more user friendly versions. For example, database value for a field:
SomeVeIRdLooking_Value
And I would like it to map to:
public enum MyEnum {
MyFormattedValue
}

You can select string values from database and convert it by hand.
public enum MyEnum
{
None,
Success,
Failure
}
var enums = connection.Query<string>("select 'None' union select 'Success' union select 'Failure'")
.Select(x => Enum.Parse(typeof (MyEnum), x)) //use your own method to parse enum from string
.ToList();

This is nearly 8 years later, but in case this helps someone else, you can correct "bad" database values with the query
SELECT *,
CASE DbColumnName
WHEN 'SomeVeIRdLooking_Value'
THEN 'MyFormattedValue'
WHEN 'SomeOtherWierd_Value'
THEN 'MyOtherFormattedValue'
ELSE DbColumnName
END AS DbColumnNameFix

Related

Entity Framework Core 2.1 System.Data.SqlClient.SqlException (0x80131904): Type Flag is not a defined system type

After upgrading to EntityFramework 2.1.11, I am facing the following issue.
System.Data.SqlClient.SqlException (0x80131904): Type Flag is not a defined system type.
I am getting this Error for Linq to SQL internal translation. There are two columns in database table which are of tinyint datatype which have corresponding C# datatype as byte, which is throwing exception in Linq while querying.
The reason is column == 1 is translated as CAST(1 AS Flag)internally in 2.1 which was working in 2.0.
It is working if we change == 1 to == Convert.ToByte(1) or assigning to byte variable and using that as == variable which I think is not the ideal fix.
This is the piece of code which is throwing error.
var query = await (from pl in _azureContext.Product.AsNoTracking()
where pl.Primary ==1 && pl.Deleted == 0
select new Product
{
ProductId = pl.ProductId,
ProductName = pl.ProductName
}).OrderBy(P => P.ProductName).ToListAsync<Product>();
SQL Internal Translation which throws exception is as follows:
SELECT [pl].[ProductId] , [pl].[ProductName] FROM [Products] AS [pl] WHERE ([pl].[Primary] = CAST(1 AS Flag)) AND ([pl].[Deleted] = CAST(0 AS Flag)) ORDER BY [pl].[ProductName]
The Expected SQL Translation is as follows:
SELECT [pl].[ProductId] , [pl].[ProductName] FROM [Products] AS [pl] WHERE ([pl].[Primary] = 1) AND ([pl].[Deleted] = 0) ORDER BY [pl].[ProductName]
It looks like a bug in Entityframework Core 2.1. Could anyone please help me on this?
Added additional information based on comments from David.
1) I haven't created any custom type for this and not missing.
2) C# datat type is Byte for pl.Primary and pl.Deleted.
3) In the dbContext I am seeing the following in onModelCreating method.
entity.Property(e => e.Primary).HasColumnType("Flag");
entity.Property(e => e.Deleted).HasColumnType("Flag");
Note: DbContext was generated earlier with .net core 2.0 and no code changes done on that.
The problem is that you have HasColumnType("Flag") in the configuration for your properties. This tells Entity Framework that the type of the column is Flag, obviously not a standard SQL Server data type. The simple solution is to remove that configuration method.
However, those columns are obviously meant to be boolean flags, and you should be using the appropriate data type. This means in C# your type is bool and in SQL Server it is bit. For example, your table would look something like this:
CREATE TABLE Products
(
-- Other columns
Primary BIT,
Deleted BIT
)
and your C# class like this
public class Product
{
// Snip other columns
public bool Primary { get; set; }
public bool Deleted { get; set; }
}

How to return a query from cosmos db order by date string?

I have a cosmos db collection. I need to query all documents and return them in order of creation date. Creation date is a defined field but for historical reason it is in string format as MM/dd/yyyy. For example: 02/09/2019. If I just order by this string, the result is chaos.
I am using linq lambda to write my query in webapi. I have tried to parse the string and try to convert the string. Both returned "method not supported".
Here is my query:
var query = Client.CreateDocumentQuery<MyModel>(CollectionLink)
.Where(f => f.ModelType == typeof(MyModel).Name.ToLower() && f.Language == getMyModelsRequestModel.Language )
.OrderByDescending(f => f.CreationDate)
.AsDocumentQuery();
Appreciate for any advice. Thanks. It will be huge effort to go back and modify the format of the field (which affects many other things). I wish to avoid it if possible.
Chen Wang.Since the order by does not support derived values or sub query(link),so you need to sort the derived values by yourself i think.
You could construct the MM/dd/yyyy to yyyymmdd by UDF in cosmos db.
udf:
function getValue(datetime){
return datetime.substring(6,10)+datetime.substring(0,2)+datetime.substring(3,5);
}
sql:
SELECT udf.getValue(c.time) as time from c
Then you could sort the array by property value of class in c# code.Please follow this case:How to sort an array containing class objects by a property value of a class instance?

Filter records using Linq on an Enum type

I'm hoping this is a simple solution. I have a field (PressType) in a table (Stocks) that is seed populated by using an Enum. The table stores the data as an integer. However when I want to query some data via Linq it gives me issues. I can filter any other fields in the table using this format however on the Enum populated field it says
the "==" operator cannot be applied to operands of type "Models.PressType" and "string".
Any help you could give would be appreciated, thanks.
var test = db.Stocks.Where(x => x.PressType == myValue);
There is nothing wrong with your Linq. Your problem is that myValue is of type string. You need to convert your string to the enum first.
string myValue = SomeControl.Text;
Models.PressType myValueAsEnum = (Models.PressType)
Enum.Parse(typeof(Models.PressType), myValue);
IQueryable<Stock> test = db.Stocks.Where(x => x.PressType == myValueAsEnum);

Request Genres by MovieId using LINQ to Netflix OData

I am trying to create a LINQ query to return genres by movieid. The LINQ works in LINQPAD4. Can someone help me with the proper syntax? I am getting the following errors:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists (are you missing a cast?)
and
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
Code:(note I have wrapped Title in the following line with parenthesis, but are actually brackets in my code.
public List(Genre) GetGenresByMovieId(string movieid)
{
var genres = from t in MovieCatalog.Titles
where t.Id == "BVlLx"
select t.Genres;
return genres.ToList();
}
The right query would look like
public IEnumerable<Genre> GetGenresByMovieId(string movieId)
{
return from title in ctx.Titles
from genre in title.Genres
where title.Id == "BVlLx"
select genre;
}
In the method call syntax, you need to use SelectMany, not Select, since the filter on titles returns a list of titles (which will always contain just one title, but the compiler doesn't know that) and so you want to "concatenate" all genres for each title in the results.
The return type is actually IQueryable, but if you only plan to enumerate over it, you can use IEnumerable, or call ToList() to force execution right there in the method (the way I wrote it the query would actually execute only once you try to enumerate it).
Your problem is your projection:
select new { Name = g.Name }
That is projecting the query into an anonymous type.
You need to project into the IQueryable you have declared (IQueryable<Genre>)
When working with LINQ queries, it's preferable to use implicitly-typed variables (var).
Also, not sure why you have that extra "from" in your query, you don't need that.
Something like this should work:
var genres = from t in MovieCatalog.Titles
where t.Id = "BVlLx"
select t.Genres;
return genres.ToList();
var genres should be typed to an IQueryable<Genre>.
That is assuming you want to return a collection of Genre objects.
If you just want the name, do this:
select t.Genres.Name
But that will return a collection of string objects (and var genres should be typed to an IQueryable<string>).
However, i have no idea about the NetFlix OData API, but that should get you on the right track.

Return Datatype of Linq Query Result

I think I'm missing something really basic.
var signatures=from person in db.People
where person.Active==true
select new{person.ID, person.Lname, person.Fname};
This linq query works, but I have no idea how to return the results as a public method of a class.
Examples always seem to show returning the whole entity (like IQueryable<People>), but in this case I only want to return a subset as SomeKindOfList<int, string, string>. Since I can't use var, what do I use?
Thanks!
You can get concrete types out of a linq query, but in your case you are constructing anonymous types by using
select new{person.ID, person.Lname, person.Fname};
If instead, you coded a class called "Person", and did this:
select new Person(peson.ID, person.Lname, person.Fname);
Your linq result (signatures) can be of type IEnumerable<Person>, and that is a type that you can return from your function.
Example:
IEnumerable<Person> signatures = from person in db.People
where person.Active==true
select new Person(person.ID, person.Lname, person.Fname);

Resources