I am wondering if there is a way, using Entity Framework, of mapping results from arbitrary sql, like ResultSetMapping in Doctrine. I know i can create a configuration class doing the mapping but that requires me registering the class as an entity type.
What i am trying to do is utilize the materialization element (Object Services) of EF without the rest of EF. Sometimes i have results from a proc with cryptic or less meaningful column names, but need to map to classes with more meaningful property names but have no permission to alter the proc definition, e.g:
exec dbo.getRecDetail #var
returning columns :
sd, ed, nm, ....
which should be mapped to a class such as:
class Obj{
public DateTime StartDate; //sd
public DateTime EndDate; //ed
public String Name; //nm
....
}
If you are using .EDMX file (designer) with database first approach you can import your stored procedures into the model (simply select stored procedures in wizard) and map their results to complex types.
It actually works with arbitrary SQL queries as well but those queries cannot be imported into the model automatically (because they don't exist in your database). It requires manual modification of storage model in EDMX file (it is XML - check documentation for Function and CommandText elements). Once you do that you cannot use update from database feature of the designer any more because it would delete your custom queries.
If you are using code first there is currently no option to map results of stored procedures or custom queries. You can only use automatic mapping which requires your class to have properties with exactly same name as columns in result sets.
Related
I typically work with my DBA to design my database tables before I begin developing. In nearly all instances, I use the varchar datatype for storing strings in my SQL database.
When I use EF Power Tools to generate my model classes, the column names and lengths get generated correctly, but I always have to go back in and specify HasColumnType("varchar"); because by default everything is nvarchar (I know this by looking at the queries EF generates and the sitautions where it needs to CAST() to varchar).
Is there any way I can generate my model classes from my database and have EF know the correct data types (varchar vs nvarchar)? Meaning, is there anyway I can auto generate my C# model class for my varchar(50) column to show as:
this.Property(t => t.MyColumn)
.HasMaxLength(50)
.HasColumnType("varchar");
Thank you.
Sure, in your OnModelCreating method, use this:
modelBuilder.Properties<string>().Configure(c => c.HasColumnType("varchar"));
In case you need to still have some string columns be NVARCHAR, you can just specify that on those specific properties after you use this command. According to Microsoft, FluentAPI operates in a "last wins" manner. So, you can do whatever you want to any property or group of properties, and if you make another change to the same property later, the one specified later will be the final result.
I currently use a database-first approach using Entity Framework (EF). I'm investigating different ways of calling stored procedures (stored procedures that are NOT tied to entities) using EF. Currently, I'm using the approach found here using the designer (in this approach, I import a stored procedure, create a function import and use a complex type as my mapped object). I don't like this because it relies on a bloated EDMX file and it causes merge conflicts in source control when two or more people perform this procedure and check in their code.
I found this post which claims I can call a stored procedure and map to a plain old C# object (POCO).
My question is if I want to map to a POCO to a stored procedure in EF not using the designer approach, how do I get aliases for column names? For example, let's say I call a stored procedure and get a particular column back named "CustomerID" and I want the property mapped to it to be named "Id" instead of "CustomerID". How can I do this without using the designer approach?
Something like the following should work:
[your db context].Database.SqlQuery<[your POCO class]>("[name of stored proc] [comma separated parameters]", parameter1, parameter2, .....)
Here's example from one of my applications:
_context.Database.SqlQuery<Library>("usp_paged_select_libraries #userId, #offset, #fetch", userIdParameter, offsetParameter, fetchParameter);
Within your POCO you would mark up your properties with:
[Column("[your alias here]")]
I have a MVC project that has a Linq to SQL dbml class. It is a table called Clients that houses client information. I can easily get the information to display in a View using the code I followed in Nerd Dinner but I have added a stored procedure to the dbml and it's result set is of IQueryable, not IQueryable. I need to convert IQueryable to IQueryable so I can display it in the same View. The reason for the sproc is so I can pass a search string tothe sproc and return the same information as a full list but filtered on the search. I know I can use Linq to filter the whole list but I don't want the whole list so I am using the sproc.
Here is the code in my ClientRepository with a comment where I need to convert. What code goes in the commented spot.
public IQueryable<Client> SelectClientsBySearch(String search)
{
IQueryable<SelectClientsBySearchResult> spClientList = (from p in db.SelectClientsBySearch(search) select p).AsQueryable();
//what is the code to convert IQueryable<SelectClientsBySearchResult> to IQueryable<Client>
return clientList;
}
If your result type and your client type match (IOW, your sproc returns Select * from Client and you haven't modified the Client entity in the DBML since adding it), you can change the stored proc to automtically return IQueryable of Client instead of IQueryable of SelectClientsBySearchResult (see instructions below). Then no conversion is necessary.
If they are different, there are a few different approaches. You can modify the partial class for your entities to add conversion methods to them, or you can use extension methods. Both of these approaches avoid overwriting when the code behind the DBML is regenerated.
To change the stored proc return type:
The DBML designer created the SelectClientsBySearchResult type for your stored proc when you added the stored proc to the DBML. This is the default behavior if you drag the proc from the server explorer to the procedures pane. Instead, drag the stored proc from the server explorer and drop it on the Client table. Now its return type is a collection of Client instead.
I believe you can also change the return type after the fact (as it is now), but I don't have it installed right now and can't guide you through it.
I am trying to get to grips with the Entity framework, and have a requirement to order results by distance from a point on the globe. I have decided on previous advice to do this using a stored procedure which I have successfully done populating a view. However I need to return multiple tables, which I understand I cannot do directly using stored Procedures on the Entity Framework. If this is not correct, I would be grateful if someone could advise how I might do this.
Anyway I therefore have defined a simple sp (SELECT id FROM table) and then wanted to perform a linq query to join this with the equivalent object in my model as follows:
var sp = db.StoredProcedure();
var ret = from x in db.X
join y in sp on x.ID equals y.ID
select x;
However when I perform this I get the following exception resulting from the query:
"Unable to create a constant value of type 'System.Collections.Generic.IEnumerable'1'.Only primitive types('suchas Int32, String, Guid') are supported in this context."
Why is this happening? Is this the right approach? (Note that my final sp will be more complex, and I will be returning multiple classes from the select in 'ret')
Use EF Extensions
Stored procedures are really badly supported in EF. Even if they return entity results, they don't provide any name mappings, so you have to rename columns in stored procedures yourself.
But. There's project called Entity Framework Extensions that will make all kinds of different scenarios with stored procedures possible.
Using EF extensions you can use stored procedures in any way you want:
you can do column remappings in your custom materializer (so your stored procedure returns same columns as they are in the DB without the need to rename columns to entity property names)
you can return multiple result sets (great for 1:* and : relations)
you can use scalar stored procedures or even procedures that don't return anything
you can consume results from a stored procedure that returns multiple entities per row (when having 1:1 relation between two of them)
you can also use output parameters which is great if you create a stored procedure that does paging (returns a subset of records as entities and returns out parameters with total count)
etc.
You can do preety much anything. We've used EF Extensions with much success on a some project. We wrote our own materializers (basically a lamba expression) for entities that our stored procedures returned. And then we materialized their results.
I don't think EF4 will support stored procedures to this level anyway, so getting acquainted to EF Extensions is always valuable.
The EF in .NET 3.5 SP1 cannot map procs which return scalar values (in .NET 4.0 you can). The SP must return all the values necessary to materialize a full entity, which is likely more than just the ID.
Also, it's almost never correct to use the "join" reserved word in LINQ to Entities. You traverse relationships in your client schema instead.
Start by writing a proc which returns all values necessary for an entity type. Map that proc. Then do:
IQueryable<MyEntity> q = from e in Context.MyEntities
select e;
Then move on from there.
I already have an entity model in a separate dll that contains various objects that I need to use. I don't really want to create or duplicate entities using the EF designer. Instead I would like to configure it so that when I call a stored procedure it will map certain columns to specific properties.
I know you can do something VERY close to this using a custom DataContext in LinqToSql. The problem is you can't assign columns to complex property types. For example: I might have a columns returned that contain the address for a user. I would like to store the address details for the user in an Address object that is a property of a User object. So, Column STREET should map to User.Address.Street.
Any ideas?
There are a couple of options here.
You can create a "Complex Type" and map that to the procedure result. However, you have to do that in your EDMX; it's not supported by the designer. Read this article for details. Note that Complex Types are not entity types per se, so this may or may not fit your needs. But you can find examples for stored procs which use "Address".
You can change the visibility of your procedure to private, and then write a public interface for it in any manually-written partial class file which does the mapping that you want. Or just overload the procedure.