Representing a tinyint field as an enum in Entity Framework - c#

I've been using Linq2Sql for the last few years and got used to a few features, like having an int or tinyint field in the DB, that I redefine in the DBML file to be of enum type, so it's nice and convenient to run a SQL query directly comparing to the enum (see here for my question 3 years ago on the subject, and the answer there).
Now I'm starting a project using Entity Framework 5, and while EF seems to have gotten many things right that L2S didn't (e.g. detach/reattach), I'm dismayed to see that there doesn't seem to be any easy way to change the C# type of such a field to be an enum.
Has anyone found a way to do this cleanly, so that I could have a query like:
var q = entities.Things.Where(t => t.Status == TStatus.Closed);
(and no, I don't want to have to cast to int or byte inline).

Code First
EF5 Code First supports enum properties on .NET 4.5. The following entity will create a int field in the database:
public class Event
{
public int EventId { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Open,
Closed,
Pending
}
To which you could query:
db.Events.Where(e => e.Status == Status.Pending)
Database First
As explained in this post, here's how you accomplish the same thing for Database First.
Go to the model browser and create a new enum type, then go to whatever column you wish to use it on and change its type to the enum that you just created.

Related

How to linq filter on multiple GUID at once generating an appropriate sql where clause

I'm having a hard time generating a properly filtered sql query with fluent API in Entity Framework core rc2-final connected to a sqlite database.
I have the following simple entity :
public class Thing
{
[Required, Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
}
I need to query the database for all books that are in a stash list of Books I provide. So far, sounds easy. This is how we could write it :
// 'GetShortListFromSomewhere' returns 2 items that ALREADY exist in db
List<Thing> externalList = GetShortListFromSomewhere();
var result = db.Things.Where(thing => externalList.Contains(o.Id)).ToList();
But the following query is generated which is kind of correct and kind of .. not .. for sqlite :
SELECT "o"."Id", "o"."Name" FROM "Thing" AS "o"
WHERE "o"."Id" IN ('7edbc016-abfa-4005-83d1-b39618b047df', '2def16bb-4203-417d-847c-7bdf053a00e8')
As expected in code, this returns me 0 items although Ids are perfectly valid. Guid on Sqlite as stored on Blob and although EF-Core seems to handle the filter nicely for single item filter, it doesn't seem to handle it in this case.
How can I get around this issue knowing that I need it to be a sql operation ?
ps: Last thing I want is for EF Core to download the whole Thing collection from db and then filter it ! It would be madness in my case.
This is issue #5801. Unfortunately, it won't be fixed for the 1.0.0 release. To workaround, map the columns to byte[] properties.

Using interfaces in LINQ database queries

I am working on part of an application that simply pulls information from the database and displays it to users. For simplicity sake, let us assume I have a database with two tables, Cats and Dogs. Both tables have manually assigned primary keys and are never duplicated/overlapped. The goal I am trying to achieve is to perform 1 LINQ query that will concat both tables.
I recently asked this question regarding performing a LINQ concat on two collections of objects, Cats and Dogs, that were manually created in code. I advise reading the previous question as it will give much insight to this one.
The reason I wish to use interfaces is to simplify my queries. I currently have a solution that .Select each of the columns I need into an anonymous type. This would work fine for this instance, but will consume pages with the data I am working with.
The different between that previous question and this one is that I am trying to pull these animals from a database. From my analysis, it seems that .NET or Entity Framework is not able to relate my database to my interface
Model (From old question)
public interface iAnimal
{
string name { get; set; }
int age { get; set; }
}
public class Dog :iAnimal
{
public string name { get; set; }
public int age { get; set; }
}
public class Cat:iAnimal
{
public string name { get; set; }
public int age { get; set; }
}
Here are some different LINQ queries I have tried and the resulting error. The first example will be using the solution from the previous question.
var model = _db.Cats.Concat<iAnimal>(_db.Dogs).Take(4);
System.ArgumentException: DbUnionAllExpression requires arguments with compatible collection ResultTypes.
Without Covariance:
var model = _db.Cats.Cast<iAnimal>().Concat(_db.Dogs.Cast<iAnimal>());
System.NotSupportedException: Unable to cast the type 'Test.Models.Cat' to type 'Test.Interfaces.iAnimals'. LINQ to Entities only supports casting Entity Data Model primitive types.
From the above error, it looks like I am not able to use interfaces to interact with databases as it is not mapped to any particular table.
Any insight would be much appreciated. Thanks
EDIT
In response to #Reed Copsey, with your solution, I get the same error as my example without covariance. I tried changing the view's type to match what the error recommends, which results in this error
System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery`1[Test.Interfaces.iAnimal]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Test.Models.Cat]'.
You database knows nothing about your interface and you will probably not be able to get this working. I see two options.
You could use inheritance - for example supported by the Entity Framework - and inherit both entities from a common base entity. Than you will be able to perform queries against the base type but this may require changes to your data model depending on the way you implement inheritance at the database level.
Have a look at the documentation for TPT inheritance and TPH inheritance. There are still other inheritance models like TPC inheritance but they currently lack designer support.
The second option is to fetch results from both tables into memory and use LINQ to Objects to merge them into a single collection.
var dogs = database.Dogs.Take(4).ToList();
var cats = database.Cats.Take(4).ToList();
var pets = dogs.Cast<IPet>().Concat(cats).ToList();
Also note that your query
var model = _db.Cats.Concat<iAnimal>(_db.Dogs).Take(4);
seems not really well designed - the result will definitely depend on the database used but I would not be surprised if you usually just get the first four cats and never see any dog.

Entity Framework storing arrays of data

I've started playing around with using Entity Framework Code-First because it looks like a nice way to get a database up and running quickly. I'm coming from a PostgreSQL background, which has support for array types in tables, for example time[]. My question is two-fold; does SQL Server support array types, and if so, how can I use them in EF? If they're not supported, what is an alternative way to represent this data?
table Venue
openhours time[]
Edit: The array above is intended to store different times for each day of the week- a venue might have different opening hours on different weekends to weekdays, for example.
No, it is not supported, you need to store your openhours in a separate table (VenueOpenhours) with a foreign key to the Venue table.
SQL Server doesn't support array types. Extrapolating from your example schema, I think an equivalent EF POCO would be the following:
public class Venue
{
public int VenueId { get; set; }
public DateTime OpenHour { get; set; }
public DateTime CloseHour { get; set; }
}
Finding whether the Venue was open at a given time would just require a range query, Venue.Where(a => a.OpenHour <= time && a.CloseHour >= time). Of course, this is a very simplistic example. Most likely you'd want to store the Venue hours in another table. But I hope this may be able to move you in the right direction.

When using MySQL, why is Entity Framework 4 trying to convert a long to a decimal?

Whenever I have a table with a BIGINT primary key, I can insert new records, but can't update existing records. When I try to do an update, I get the following error:
"The specified value is not an instance of type 'Edm.Decimal'"
Sample model:
public class Model
{
public long ModelID { get; set; }
public DateTime ProcessedOn { get; set; }
}
Sample update code:
public bool SetModelProcessed(long id)
{
var entity = db.models.SingleOrDefault(m => m.ModelID == id);
entity.ProcessedOn = DateTime.Now;
db.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
db.SaveChanges();
}
Even a model as simple as this one is failing for me. Anyone know what is happening?
Edit
I tried the code-first approach. Entity Framework 4.3 couldn't even generate the mySQL database which is apparently an issue for mySQL and versions of Entity Framework after the migration features were added.
Since downgrading to version 4.1.10715.0, long works, ulong still doesn't. EF won't acknowledge a property as the primary key if it's a ulong.
EntityType 'Model' has no key defined. Define the key for this EntityType.
Using long instead of ulong isn't what I need, but it'll have to do I guess.
If this happens to be an unsigned bigint in the database, then I believe it gets mapped to a decimal instead of a long - not sure why it doesn't just use a ulong. But I'd start there, make sure your bigint is signed.
Many years later...
Use HasColumnType("long") in the OnModelCreating() method of your DbContext.
See Entity Framework Core will not map to BigInteger

Generics and database - a design issue

The situation is that I have a table that models an entity. This entity has a number of properties (each identified by a column in the table). The thing is that in the future I'd need to add new properties or remove some properties. The problem is how to model both the database and the corresponding code (using C#) so that when such an occasion appears it would be very easy to just "have" a new property.
In the beginning there was only one property so I had one column. I defined the corresponding property in the class, with the appropriate type and name, then created stored procedures to read it and update it. Then came the second property, quickly copy-pasted, changed name and type and a bit of SQL and there it was. Obviously this is not a suitable model going forward. By this time some of you might suggest an ORM (EF or another) because this will generate the SQL and code automatically but for now this is not an option for me.
I thought of having only one procedure for reading one property (by property name) and another one to update it (by name and value) then some general procedures for reading a bunch or all properties for an entity in the same statement. This may sound easy in C# if you consider using generics but the database doesn't know generics so it's not possible to have a strong typed solution.
I would like to have a solution that's "as strongly-typed as possible" so I don't need to do a lot of casting and parsing. I would define the available properties in code so you don't go guessing what you have available and use magic strings and the like. Then the process of adding a new property in the system would only mean adding a new column to the table and adding a new property "definition" in code (e.g. in an enum).
It sounds like you want to do this:
MyObj x = new MyObj();
x.SomeProperty = 10;
You have a table created for that, but you dont want to keep altering that table when you add
x.AnotherProperty = "Some String";
You need to normalize the table data like so:
-> BaseTable
RecordId, Col1, Col2, Col3
-> BaseTableProperty
PropertyId, Name
-> BaseTableValue
ValueId, RecordId, PropertyId, Value
Your class would look like so:
public class MyObj
{
public int Id { get; set; }
public int SomeProperty { get; set; }
public string AnotherProperty { get; set; }
}
When you create your object from your DL, you enumerate the record set. You then write code once that inspect the property as the same name as your configuration (BaseTableProperty.Name == MyObj.<PropertyName> - and then attempt the type cast to that type as you enumerate the record set.
Then, you simply add another property to your object, another record to the database in BaseTableProperty, and then you can store values for that guy in BaseTableValue.
Example:
RecordId
========
1
PropertyId Name
========== ====
1 SomeProperty
ValueId RecordId PropertyId Value
======= ======== ========== =====
1 1 1 100
You have two result sets, one for basic data, and one joined from the Property and Value tables. As you enumerate each record, you see a Name of SomeProperty - does typeof(MyObj).GetProperty("SomeProperty") exist? Yes? What it it's data type? int? Ok, then try to convert "100" to int by setting the property:
propertyInfo.SetValue(myNewObjInstance, Convert.ChangeType(dbValue, propertyInfo.PropertyType), null);
For each property.
Even if you said you cannot use them, that is what most ORM do. Depending on which one you use (or even create if it's a learning experience), they will greatly vary in complexity and performance. If you prefer a light weight ORM, check Dapper.Net. It makes use of generics as well, so you can check the code, see how it works, and create your own solution if needed.

Categories

Resources